From 87967f6dad187a626b2069ed6f2125648be7497f Mon Sep 17 00:00:00 2001 From: Steve Chan <> Date: Thu, 7 Aug 2025 17:08:42 -0400 Subject: [PATCH 01/11] chore: fix the ci to install the test requisites --- .github/workflows/ci.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 80fb0c02..574a0b5d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ concurrency: jobs: test-precommit: - runs-on: ubuntu-22.04-16core + runs-on: ubuntu-24.04 steps: - name: Checkout code @@ -31,6 +31,8 @@ jobs: cache: false cache-write: ${{ github.event_name == 'push' && github.ref_name == 'main' }} + - name: Add test requirements + run: pixi add pre-commit pyright - name: Check formatting and typing run: | set -e @@ -45,7 +47,7 @@ jobs: test-esm: - runs-on: ubuntu-22.04-16core + runs-on: ubuntu-24.04 steps: - name: Checkout code @@ -80,6 +82,9 @@ jobs: run: | docker rm --force --volumes $(docker ps -q) || true + - name: Add test requirements + run: pixi add pytest + # Next two steps adds a comment to any PR that reports tests + code coverage. - name: Pytest Coverage Comment if: ${{ github.event_name == 'pull_request' }} @@ -90,6 +95,7 @@ jobs: pytest-coverage-path: pytest-coverage.txt junitxml-path: pytest.xml report-only-changed-files: true + shell: pixi run bash -e {0} - name: Pytest coverage GitHub summary if: ${{ github.event_name == 'pull_request' }} From d8d04ecc9289ad73710c60468e27b90366f63a20 Mon Sep 17 00:00:00 2001 From: Steve Chan <> Date: Thu, 7 Aug 2025 17:24:17 -0400 Subject: [PATCH 02/11] proper placement for pytest stuff --- .github/workflows/ci.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 574a0b5d..8298f2fe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,6 +60,9 @@ jobs: cache: false cache-write: ${{ github.event_name == 'push' && github.ref_name == 'main' }} + - name: Add test requirements + run: pixi add pytest + - name: Run tests run: | set -o pipefail @@ -82,9 +85,6 @@ jobs: run: | docker rm --force --volumes $(docker ps -q) || true - - name: Add test requirements - run: pixi add pytest - # Next two steps adds a comment to any PR that reports tests + code coverage. - name: Pytest Coverage Comment if: ${{ github.event_name == 'pull_request' }} @@ -95,7 +95,6 @@ jobs: pytest-coverage-path: pytest-coverage.txt junitxml-path: pytest.xml report-only-changed-files: true - shell: pixi run bash -e {0} - name: Pytest coverage GitHub summary if: ${{ github.event_name == 'pull_request' }} From 7aee7e9d2ed60343b691a1202a5589ba4a4bf376 Mon Sep 17 00:00:00 2001 From: Steve Chan <> Date: Fri, 8 Aug 2025 09:43:58 -0400 Subject: [PATCH 03/11] add precommit config --- .pre-commit-config.yaml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..0ec4d845 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,32 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.2.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + exclude: scripts/conda + - id: check-added-large-files + - id: check-merge-conflict +- repo: https://github.com/seddonym/import-linter + rev: v1.12.1 + hooks: + - id: import-linter +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.7.3 + hooks: + - id: ruff # linter + args: [ --fix ] + - id: ruff-format # formatter + types_or: [python, jupyter] +- repo: https://github.com/RobertCraigie/pyright-python + rev: v1.1.399 + hooks: + - id: pyright + name: pyright + entry: pyright + language: system + types: [python] + pass_filenames: true # For speed, we only check the files that are changed From 99d867c4277f74d8089eb95d51d7f02548e0098c Mon Sep 17 00:00:00 2001 From: Steve Chan <> Date: Fri, 8 Aug 2025 10:16:57 -0400 Subject: [PATCH 04/11] rearrange test tasks --- .github/workflows/ci.yml | 21 ++------------------- .pre-commit-config.yaml | 1 - pyproject.toml | 12 ++++++++++++ 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8298f2fe..b2c7b59d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,19 +31,8 @@ jobs: cache: false cache-write: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - - name: Add test requirements - run: pixi add pre-commit pyright - name: Check formatting and typing - run: | - set -e - # pyright seems to do something weird at initialization that causes it to error out - # We can ignore the first invocation here. - pyright esm/__init__.py || true - pre-commit install - env NODE_OPTIONS="--max-old-space-size=16384" pre-commit run --all-files --show-diff-on-failure - [ -z "$(git status --porcelain)" ] && true || (echo "❌❌❌ pre-commit hook failed! A few files changed ❌❌❌]" && git status --porcelain && false) - git reset --hard HEAD # test without the pre-commit changes - shell: pixi run bash -e {0} + run: pixi run lint test-esm: @@ -60,14 +49,8 @@ jobs: cache: false cache-write: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - - name: Add test requirements - run: pixi add pytest - - name: Run tests - run: | - set -o pipefail - pytest -v --junitxml=pytest.xml tests/ | tee pytest-coverage.txt - shell: pixi run bash -e {0} + run: pixi run test - name: Run Docker tests env: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0ec4d845..2ccba59b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,6 @@ repos: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - exclude: scripts/conda - id: check-added-large-files - id: check-merge-conflict - repo: https://github.com/seddonym/import-linter diff --git a/pyproject.toml b/pyproject.toml index 8ab5b091..081583af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,3 +67,15 @@ esm = { path = ".", editable = true } [tool.pixi.tasks] build-wheel = "python -m pip wheel --no-deps -w dist ." upload-wheel = "python -m twine upload --repository pypi" + +[tool.pixi.feature.dev.dependencies] +pytest = "*" +pre-commit = "*" + +[tool.pixi.feature.dev.tasks] +lint = "pre-commit --all-files --show-diff-on-failure" +test = "pytest -v --junitxml=pytest.xml | tee pytest-coverage.txt" + +[tool.pixi.environments] +default = {features = [], solve-group = "default"} +dev = {features = ["dev"], solve-group = "default"} From b2e5a5674b3e26474b40940973d6d513bd87ad37 Mon Sep 17 00:00:00 2001 From: Steve Chan <> Date: Fri, 8 Aug 2025 14:25:18 +0000 Subject: [PATCH 05/11] fix test imports --- .github/workflows/ci.yml | 4 +- pixi.lock | 2341 ++++++++++++++++++++++++++++++++++---- pyproject.toml | 9 +- 3 files changed, 2116 insertions(+), 238 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b2c7b59d..9482116d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: cache-write: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - name: Check formatting and typing - run: pixi run lint + run: pixi run lint-all test-esm: @@ -50,7 +50,7 @@ jobs: cache-write: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - name: Run tests - run: pixi run test + run: pixi run cov-test - name: Run Docker tests env: diff --git a/pixi.lock b/pixi.lock index d3fa4fa3..d635cac5 100644 --- a/pixi.lock +++ b/pixi.lock @@ -26,6 +26,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.7.0-h5888daf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.18.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.2.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda @@ -40,26 +41,42 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/keyring-25.6.0-pyha804496_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.17-h717163a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h0aef613_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-31_h59b9bed_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-31_he106b2a_openblas.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.13.0-h332b0f4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.23-h86f0d12_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.0-h5888daf_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.6-h2dba641_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.13.3-ha770c72_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.13.3-h48d6fc4_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h767d61c_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.2.0-h69a702a_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.84.0-h2ff4ddf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-14.2.0-h69a702a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.2.0-hf1ad2bd_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.84.1-h2ff4ddf_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.2.0-h767d61c_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h4ce23a2_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.0-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-31_h7ac8fdf_openblas.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.6.4-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.64.0-h161d5f1_0.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/libopenblas-0.3.29-pthreads_h94d23a6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.50-h421ea60_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.49.1-hee588c1_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hf672d98_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-14.2.0-h8f9b012_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-14.2.0-h4852527_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.0-hd9ff511_3.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/libuv-1.50.0-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_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-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-3.0.0-pyhd8ed1ab_1.conda @@ -67,17 +84,26 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.6.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nh3-0.2.21-py39h77e2912_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.3.2-py312h33ff503_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.3-h55fea9a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.1-h7b32b05_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-2.3.1-py312hf79963d_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.44-hba22ea6_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-11.3.0-py312h80c1187_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.0.1-pyh8b19718_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h4bc722e_1009.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.9-h9e4cc4f_1_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.9-hd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.12-6_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.2-py312h178313f_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8c095d6_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/readme_renderer-44.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.3-pyhd8ed1ab_1.conda @@ -85,17 +111,23 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/rfc3986-2.0.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/rhash-1.4.5-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/rich-14.0.0-pyh29332c3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.16.0-py312hf734454_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/secretstorage-3.3.3-py312h7900ff3_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-75.8.2-pyhff2d567_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_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/twine-6.1.0-pyh29332c3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.13.0-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.45.1-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.21.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py312h66e93f0_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda + - pypi: https://files.pythonhosted.org/packages/6f/12/e5e0282d673bb9746bacfb6e2dba8719989d3660cdb2ea79aee9a9651afb/anyio-4.10.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b4/0d/b7a0f10f5100dcf51ae36ba31490169bfa45617323bd82af43e1fb0098fb/biopython-1.85-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl @@ -105,8 +137,10 @@ environments: - pypi: https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/87/62/9773de14fe6c45c23649e98b83231fffd7b9892b6cf863251dc2afa73643/einops-0.8.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/44/4b/e0cfc1a6f17e990f3e64b7d941ddc4acdc7b19d6edd51abf495f32b1a9e4/fsspec-2025.3.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/99/e3/2232d0e726d4d6ea69643b9593d97d0e7e6ea69c2fe9ed5de34d476c1c47/huggingface_hub-0.30.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/20/3a/917cb9e72f4e1a4ea13c862533205ae1319bd664119189ee5cc9e4e95ebf/ipython-9.0.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl @@ -119,7 +153,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/f1/54/65af8de681fa8255402c80eda2a501ba467921d5a7a028c9c22a2c2eedb5/msgpack-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/9b/5d/f25ac7d4fb77cbd53ddc6d05d833c6bf52b12770a44fa9a447eed470ca9a/msgpack_numpy-0.4.8-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/02/e2/e2cbb8d634151aab9528ef7b8bab52ee4ab10e076509285602c2a3a686e0/numpy-2.2.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/ae/71/1c91302526c45ab494c23f61c7a84aa568b8c1f9d196efa5993957faf906/nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/67/42/f4f60238e8194a3106d06a058d494b18e006c10bb2b915655bd9f6ea4cb1/nvidia_cuda_cupti_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/2c/14/91ae57cd4db3f9ef7aa99f4019cfa8d54cb4caa7e00975df6467e9725a9f/nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl @@ -133,21 +166,297 @@ environments: - pypi: https://files.pythonhosted.org/packages/df/99/12cd266d6233f47d00daf3a72739872bdc10267d0383508b0b9c84a18bb6/nvidia_nccl_cu12-2.21.5-py3-none-manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/ff/ff/847841bacfbefc97a00036e0fce5a0f086b640756dc38caea5e1bb002655/nvidia_nvjitlink_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/87/20/199b8713428322a2f22b722c62b8cc278cc53dffa9705d744484b5035ee9/nvidia_nvtx_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/38/f8/d8fddee9ed0d0c0f4a2132c1dfcf0e3e53265055da8df952a53e7eaf178c/pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/38/0d/84200ed6a871ce386ddc82904bfadc0c6b28b0c0ec78176871a4679e40b3/pillow-11.1.0-cp312-cp312-manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/e4/ea/d836f008d33151c7a1f62caf3d8dd782e4d15f6a43897f64480c2b8de2ad/prompt_toolkit-3.0.50-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/a6/f8/dae3421624fcc87a89d42e1898a798bc7ff72c61f38973a65d60df8f124c/safetensors-0.5.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/29/7a/8bce8968883e9465de20be15542f4c7e221952441727c4dad24d534c6d99/scikit_learn-1.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/c0/53/eaada1a414c026673eb983f8b4a55fe5eb172725d33d62c1b21f63ff6ca4/scipy-1.15.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b2/fe/81695a1aa331a842b582453b605175f419fe8540355886031328089d840a/sympy-1.13.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8a/63/38be071b0c8e06840bc6046991636bcb30c27f6bb1e670f4f4bc87cf49cc/tokenizers-0.21.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/e5/35/0c52d708144c2deb595cd22819a609f78fdd699b95ff6f0ebcd456e3c7c1/torch-2.6.0-cp312-cp312-manylinux1_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/65/13/26c37c5433658d3f1eb30be07a4b42b29893bc42ff7cb7261ef6e474fc3c/torchtext-0.18.0-cp312-cp312-manylinux1_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/36/63/0722e153fd27d64d5b0af45b5c8cb0e80b35a68cf0130303bc9a8bb095c7/torchvision-0.21.0-cp312-cp312-manylinux1_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/9f/92d3091c44cb19add044064af1bf1345cd35fbb84d32a3690f912800a295/transformers-4.48.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/06/00/59500052cb1cf8cf5316be93598946bc451f14072c6ff256904428eaf03c/triton-3.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/92/a7/5f4c6c2a62dd88f58133e333af1c251dd08f98d48445f650889d85e43b7b/zstd-1.5.6.7.tar.gz + - pypi: ./ + dev: + channels: + - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.14-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_5.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports.tarfile-1.2.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.1.0-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py312h2ec8cdc_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.4-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2025.1.31-hbcca054_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.4-h3394656_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2025.1.31-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-1.17.1-py312h06ac9bb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.3.1-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cmake-4.0.0-h74e3db0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cmarkgfm-2024.11.20-py312h66e93f0_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.3-py312hd9148b4_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.9-py312hd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cryptography-44.0.2-py312hda17c39_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.27-h54b06d7_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/double-conversion-3.3.1-h5888daf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.7.0-h5888daf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.18.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.15.0-h7e30c49_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.59.0-py312h8a5da7c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/freetype-2.13.3-ha770c72_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.14-hecca717_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-11.2.1-h3beb420_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/id-1.5.0-pyh29332c3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.12-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.10-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.6.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.4.0-pyhd8ed1ab_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.context-6.0.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.functools-4.1.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jeepney-0.9.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/keyring-25.6.0-pyha804496_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.8-py312h68727a3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.17-h717163a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h0aef613_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-31_h59b9bed_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.1.0-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.1.0-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-31_he106b2a_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp20.1-20.1.4-default_h1df26ce_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang13-20.1.4-default_he06ed0a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-hb8b1518_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.13.0-h332b0f4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.23-h86f0d12_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.125-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.0-h5888daf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.6-h2dba641_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.13.3-ha770c72_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.13.3-h48d6fc4_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h767d61c_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.2.0-h69a702a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-14.2.0-h69a702a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.2.0-hf1ad2bd_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.84.1-h2ff4ddf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.2.0-h767d61c_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h4ce23a2_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.0-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-31_h7ac8fdf_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm20-20.1.4-he9d0ab4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.6.4-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.64.0-h161d5f1_0.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/libntlm-1.8-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.29-pthreads_h94d23a6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.50-h421ea60_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libpq-17.4-h27ae623_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.49.1-hee588c1_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hf672d98_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-14.2.0-h8f9b012_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-14.2.0-h4852527_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.0-hd9ff511_3.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/libuv-1.50.0-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_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/libxkbcommon-1.9.2-h65c71a3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.7-h8d12d68_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.39-h76b75d6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-3.0.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.10.5-py312h7900ff3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.5-py312he3d6523_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_6.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_6.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nh3-0.2.21-py39h77e2912_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.9.1-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.3.2-py312h33ff503_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.3-h55fea9a_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.9-he970967_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.1-h7b32b05_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-2.3.1-py312hf79963d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.1-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.44-hba22ea6_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-11.3.0-py312h80c1187_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.0.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h537e5f6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h4bc722e_1009.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.8-pyhe01879c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.2.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.3-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.9.0-py312h91f0f75_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-8.4.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.9-h9e4cc4f_1_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.9-hd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.12-6_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.2-py312h178313f_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.9.0-h6441bc3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8c095d6_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/readme_renderer-44.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.3-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-1.0.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rfc3986-2.0.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/rhash-1.4.5-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-14.0.0-pyh29332c3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.16.0-py312hf734454_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/seaborn-0.13.2-hd8ed1ab_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/seaborn-base-0.13.2-pyhd8ed1ab_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/secretstorage-3.3.3-py312h7900ff3_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-75.8.2-pyhff2d567_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/statsmodels-0.14.5-py312h8b63200_0.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/tomli-2.2.1-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.1-py312h66e93f0_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/twine-6.1.0-pyh29332c3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.13.0-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.0.1-py312h68727a3_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-16.0.0-py312h66e93f0_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.33.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.24.0-h3e06ad9_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.45.1-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-h4f16b4b_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-cursor-0.1.5-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-hb711507_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.1-hb711507_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.10-hb711507_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.2-hb711507_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.45-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.2-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.6-he73a12e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.12-h4f16b4b_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcomposite-0.4.6-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcursor-1.2.3-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdamage-1.1.6-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.6-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.1-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxi-1.8.2-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.4-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxtst-1.2.5-hb9d3cd8_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.6-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.21.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py312h66e93f0_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda + - pypi: https://files.pythonhosted.org/packages/6f/12/e5e0282d673bb9746bacfb6e2dba8719989d3660cdb2ea79aee9a9651afb/anyio-4.10.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b4/0d/b7a0f10f5100dcf51ae36ba31490169bfa45617323bd82af43e1fb0098fb/biopython-1.85-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/3e/04/3f09ba937cdd5381743ffabd48c18d790a684a11fb6b23dfd8d30f0ec858/biotite-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/80/cd/c607b6337ddcf55cc0249527819b727ef28481d7c56ace54cca69400c2b9/biotraj-1.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/e8/0f/b1a9b09a84ef98b9fc38d50c6b2815cb2256b804a78e7d838ddfbdc035c7/cloudpathlib-0.21.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/87/62/9773de14fe6c45c23649e98b83231fffd7b9892b6cf863251dc2afa73643/einops-0.8.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/44/4b/e0cfc1a6f17e990f3e64b7d941ddc4acdc7b19d6edd51abf495f32b1a9e4/fsspec-2025.3.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/99/e3/2232d0e726d4d6ea69643b9593d97d0e7e6ea69c2fe9ed5de34d476c1c47/huggingface_hub-0.30.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/20/3a/917cb9e72f4e1a4ea13c862533205ae1319bd664119189ee5cc9e4e95ebf/ipython-9.0.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/91/29/df4b9b42f2be0b623cbd5e2140cafcaa2bef0759a00b7b70104dcfe2fb51/joblib-1.4.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f1/54/65af8de681fa8255402c80eda2a501ba467921d5a7a028c9c22a2c2eedb5/msgpack-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/9b/5d/f25ac7d4fb77cbd53ddc6d05d833c6bf52b12770a44fa9a447eed470ca9a/msgpack_numpy-0.4.8-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ae/71/1c91302526c45ab494c23f61c7a84aa568b8c1f9d196efa5993957faf906/nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/67/42/f4f60238e8194a3106d06a058d494b18e006c10bb2b915655bd9f6ea4cb1/nvidia_cuda_cupti_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/2c/14/91ae57cd4db3f9ef7aa99f4019cfa8d54cb4caa7e00975df6467e9725a9f/nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/ea/27/1795d86fe88ef397885f2e580ac37628ed058a92ed2c39dc8eac3adf0619/nvidia_cuda_runtime_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/9f/fd/713452cd72343f682b1c7b9321e23829f00b842ceaedcda96e742ea0b0b3/nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/27/94/3266821f65b92b3138631e9c8e7fe1fb513804ac934485a8d05776e1dd43/nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/8a/6d/44ad094874c6f1b9c654f8ed939590bdc408349f137f9b98a3a23ccec411/nvidia_curand_cu12-10.3.5.147-py3-none-manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/3a/e1/5b9089a4b2a4790dfdea8b3a006052cfecff58139d5a4e34cb1a51df8d6f/nvidia_cusolver_cu12-11.6.1.9-py3-none-manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/db/f7/97a9ea26ed4bbbfc2d470994b8b4f338ef663be97b8f677519ac195e113d/nvidia_cusparse_cu12-12.3.1.170-py3-none-manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/78/a8/bcbb63b53a4b1234feeafb65544ee55495e1bb37ec31b999b963cbccfd1d/nvidia_cusparselt_cu12-0.6.2-py3-none-manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/df/99/12cd266d6233f47d00daf3a72739872bdc10267d0383508b0b9c84a18bb6/nvidia_nccl_cu12-2.21.5-py3-none-manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/ff/ff/847841bacfbefc97a00036e0fce5a0f086b640756dc38caea5e1bb002655/nvidia_nvjitlink_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/87/20/199b8713428322a2f22b722c62b8cc278cc53dffa9705d744484b5035ee9/nvidia_nvtx_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e4/ea/d836f008d33151c7a1f62caf3d8dd782e4d15f6a43897f64480c2b8de2ad/prompt_toolkit-3.0.50-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/a6/f8/dae3421624fcc87a89d42e1898a798bc7ff72c61f38973a65d60df8f124c/safetensors-0.5.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/29/7a/8bce8968883e9465de20be15542f4c7e221952441727c4dad24d534c6d99/scikit_learn-1.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b2/fe/81695a1aa331a842b582453b605175f419fe8540355886031328089d840a/sympy-1.13.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl @@ -160,7 +469,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7b/9f/92d3091c44cb19add044064af1bf1345cd35fbb84d32a3690f912800a295/transformers-4.48.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/06/00/59500052cb1cf8cf5316be93598946bc451f14072c6ff256904428eaf03c/triton-3.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/92/a7/5f4c6c2a62dd88f58133e333af1c251dd08f98d48445f650889d85e43b7b/zstd-1.5.6.7.tar.gz - pypi: ./ @@ -197,6 +505,28 @@ packages: purls: [] size: 8283 timestamp: 1736938720099 +- conda: https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.14-hb9d3cd8_0.conda + sha256: b9214bc17e89bf2b691fad50d952b7f029f6148f4ac4fe7c60c08f093efdf745 + md5: 76df83c2a9035c54df5d04ff81bcc02d + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: LGPL-2.1-or-later + license_family: GPL + purls: [] + size: 566531 + timestamp: 1744668655747 +- pypi: https://files.pythonhosted.org/packages/6f/12/e5e0282d673bb9746bacfb6e2dba8719989d3660cdb2ea79aee9a9651afb/anyio-4.10.0-py3-none-any.whl + name: anyio + version: 4.10.0 + sha256: 60e474ac86736bbfd6f210f7a61218939c318f43f9972497381f1c5e930ed3d1 + requires_dist: + - exceptiongroup>=1.0.2 ; python_full_version < '3.11' + - idna>=2.8 + - sniffio>=1.1 + - typing-extensions>=4.5 ; python_full_version < '3.13' + - trio>=0.26.1 ; extra == 'trio' + requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl name: asttokens version: 3.0.0 @@ -311,6 +641,33 @@ packages: - psutil ; extra == 'test' - netcdf4>=1.7.1 ; extra == 'test' requires_python: '>=3.10' +- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hb9d3cd8_2.conda + sha256: fcb0b5b28ba7492093e54f3184435144e074dfceab27ac8e6a9457e736565b0b + md5: 98514fe74548d768907ce7a13f680e8f + depends: + - __glibc >=2.17,<3.0.a0 + - brotli-bin 1.1.0 hb9d3cd8_2 + - libbrotlidec 1.1.0 hb9d3cd8_2 + - libbrotlienc 1.1.0 hb9d3cd8_2 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 19264 + timestamp: 1725267697072 +- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.1.0-hb9d3cd8_2.conda + sha256: 261364d7445513b9a4debc345650fad13c627029bfc800655a266bf1e375bc65 + md5: c63b5e52939e795ba8d26e35d767a843 + depends: + - __glibc >=2.17,<3.0.a0 + - libbrotlidec 1.1.0 hb9d3cd8_2 + - libbrotlienc 1.1.0 hb9d3cd8_2 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 18881 + timestamp: 1725267688731 - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py312h2ec8cdc_2.conda sha256: f2a59ccd20b4816dea9a2a5cb917eb69728271dbf1aeab4e1b7e609330a50b6f md5: b0b867af6fc74b2a0aa206da29c0f3cf @@ -357,6 +714,32 @@ packages: purls: [] size: 158144 timestamp: 1738298224464 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.4-h3394656_0.conda + sha256: 3bd6a391ad60e471de76c0e9db34986c4b5058587fbf2efa5a7f54645e28c2c7 + md5: 09262e66b19567aff4f592fb53b28760 + depends: + - __glibc >=2.17,<3.0.a0 + - fontconfig >=2.15.0,<3.0a0 + - fonts-conda-ecosystem + - freetype >=2.12.1,<3.0a0 + - icu >=75.1,<76.0a0 + - libexpat >=2.6.4,<3.0a0 + - libgcc >=13 + - libglib >=2.82.2,<3.0a0 + - libpng >=1.6.47,<1.7.0a0 + - libstdcxx >=13 + - libxcb >=1.17.0,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - pixman >=0.44.2,<1.0a0 + - xorg-libice >=1.1.2,<2.0a0 + - xorg-libsm >=1.2.5,<2.0a0 + - xorg-libx11 >=1.8.11,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + - xorg-libxrender >=0.9.12,<0.10.0a0 + license: LGPL-2.1-only or MPL-1.1 + purls: [] + size: 978114 + timestamp: 1741554591855 - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2025.1.31-pyhd8ed1ab_0.conda sha256: 42a78446da06a2568cb13e69be3355169fbd0ea424b00fc80b7d840f5baaacf3 md5: c207fa5ac7ea99b149344385a9c0880d @@ -383,6 +766,17 @@ packages: - pkg:pypi/cffi?source=hash-mapping size: 294403 timestamp: 1725560714366 +- conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.3.1-pyhd8ed1ab_1.conda + sha256: d5696636733b3c301054b948cdd793f118efacce361d9bd4afb57d5980a9064f + md5: 57df494053e17dce2ac3a0b33e1b2a2e + depends: + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cfgv?source=hash-mapping + size: 12973 + timestamp: 1734267180483 - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.1-pyhd8ed1ab_0.conda sha256: 4e0ee91b97e5de3e74567bdacea27f0139709fceca4db8adffbe24deffccb09b md5: e83a31202d1c0a000fce3e9cf3825875 @@ -444,6 +838,33 @@ packages: - pkg:pypi/cmarkgfm?source=hash-mapping size: 139452 timestamp: 1732193337513 +- conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + sha256: ab29d57dc70786c1269633ba3dff20288b81664d3ff8d21af995742e2bb03287 + md5: 962b9857ee8e7018c22f2776ffa0b2d7 + depends: + - python >=3.9 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/colorama?source=hash-mapping + size: 27011 + timestamp: 1733218222191 +- conda: https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.3-py312hd9148b4_1.conda + sha256: d9cb7f97a184a383bf0c72e1fa83b983a1caa68d7564f4449a4de7c97df9cb3f + md5: e25ed6c2e3b1effedfe9cd10a15ca8d8 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + - numpy >=1.25 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/contourpy?source=compressed-mapping + size: 291827 + timestamp: 1754063770363 - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.9-py312hd8ed1ab_1.conda noarch: generic sha256: 58a637bc8328b115c9619de3fcd664ec26662083319e3c106917a1b3ee4d7594 @@ -473,6 +894,31 @@ packages: - pkg:pypi/cryptography?source=hash-mapping size: 1590060 timestamp: 1740893871300 +- conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda + sha256: 9827efa891e507a91a8a2acf64e210d2aff394e1cde432ad08e1f8c66b12293c + md5: 44600c4667a319d67dbe0681fc0bc833 + depends: + - python >=3.9 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/cycler?source=hash-mapping + size: 13399 + timestamp: 1733332563512 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.27-h54b06d7_7.conda + sha256: d2ea5e52da745c4249e1a818095a28f9c57bd4df22cbfc645352defa468e86c2 + md5: dce22f70b4e5a407ce88f2be046f4ceb + depends: + - krb5 >=1.21.1,<1.22.0a0 + - libgcc-ng >=12 + - libntlm + - libstdcxx-ng >=12 + - openssl >=3.1.1,<4.0a0 + license: BSD-3-Clause-Attribution + license_family: BSD + purls: [] + size: 219527 + timestamp: 1690061203707 - conda: https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2 sha256: 8f5f995699a2d9dbdd62c61385bfeeb57c82a681a7c8c5313c395aa0ccab68a5 md5: ecfff944ba3960ecb334b9a2663d708d @@ -490,6 +936,17 @@ packages: version: 5.2.1 sha256: d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a requires_python: '>=3.8' +- conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + sha256: 6d977f0b2fc24fee21a9554389ab83070db341af6d6f09285360b2e09ef8b26e + md5: 003b8ba0a94e2f1e117d0bd46aebc901 + depends: + - python >=3.9 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/distlib?source=hash-mapping + size: 275642 + timestamp: 1752823081585 - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_1.conda sha256: fa5966bb1718bbf6967a85075e30e4547901410cc7cb7b16daf68942e9a94823 md5: 24c1ca34138ee57de72a943237cde4cc @@ -500,6 +957,18 @@ packages: - pkg:pypi/docutils?source=hash-mapping size: 402700 timestamp: 1733217860944 +- conda: https://conda.anaconda.org/conda-forge/linux-64/double-conversion-3.3.1-h5888daf_0.conda + sha256: 1bcc132fbcc13f9ad69da7aa87f60ea41de7ed4d09f3a00ff6e0e70e1c690bc2 + md5: bfd56492d8346d669010eccafe0ba058 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libstdcxx >=13 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 69544 + timestamp: 1739569648873 - pypi: https://files.pythonhosted.org/packages/87/62/9773de14fe6c45c23649e98b83231fffd7b9892b6cf863251dc2afa73643/einops-0.8.1-py3-none-any.whl name: einops version: 0.8.1 @@ -508,7 +977,7 @@ packages: - pypi: ./ name: esm version: 3.2.1 - sha256: 185b48ecfe9e718846b1d103c1c5a3e9abd737f986bf122801a81ff18c721afd + sha256: 12aa537c769449af8db7d3bcbe48d17b745871f014bba3d7826688770faee298 requires_dist: - torch>=2.2.0 - torchvision @@ -524,10 +993,22 @@ packages: - attrs - pandas - cloudpathlib + - httpx - tenacity - zstd requires_python: '>=3.10' editable: true +- conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda + sha256: ce61f4f99401a4bd455b89909153b40b9c823276aefcbb06f2044618696009ca + md5: 72e42d28960d875c7654614f8b50939a + depends: + - python >=3.9 + - typing_extensions >=4.6.0 + license: MIT and PSF-2.0 + purls: + - pkg:pypi/exceptiongroup?source=hash-mapping + size: 21284 + timestamp: 1746947398083 - pypi: https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl name: executing version: 2.2.0 @@ -553,25 +1034,113 @@ packages: purls: [] size: 140050 timestamp: 1743431809745 -- pypi: https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl - name: filelock - version: 3.18.0 - sha256: c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de - requires_dist: - - furo>=2024.8.6 ; extra == 'docs' - - sphinx-autodoc-typehints>=3 ; extra == 'docs' - - sphinx>=8.1.3 ; extra == 'docs' - - covdefaults>=2.3 ; extra == 'testing' - - coverage>=7.6.10 ; extra == 'testing' - - diff-cover>=9.2.1 ; extra == 'testing' - - pytest-asyncio>=0.25.2 ; extra == 'testing' - - pytest-cov>=6 ; extra == 'testing' - - pytest-mock>=3.14 ; extra == 'testing' - - pytest-timeout>=2.3.1 ; extra == 'testing' - - pytest>=8.3.4 ; extra == 'testing' - - virtualenv>=20.28.1 ; extra == 'testing' - - typing-extensions>=4.12.2 ; python_full_version < '3.11' and extra == 'typing' - requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.18.0-pyhd8ed1ab_0.conda + sha256: de7b6d4c4f865609ae88db6fa03c8b7544c2452a1aa5451eb7700aad16824570 + md5: 4547b39256e296bb758166893e909a7c + depends: + - python >=3.9 + license: Unlicense + purls: + - pkg:pypi/filelock?source=hash-mapping + size: 17887 + timestamp: 1741969612334 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 + sha256: 58d7f40d2940dd0a8aa28651239adbf5613254df0f75789919c4e6762054403b + md5: 0c96522c6bdaed4b1566d11387caaf45 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 397370 + timestamp: 1566932522327 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2 + sha256: c52a29fdac682c20d252facc50f01e7c2e7ceac52aa9817aaf0bb83f7559ec5c + md5: 34893075a5c9e55cdafac56607368fc6 + license: OFL-1.1 + license_family: Other + purls: [] + size: 96530 + timestamp: 1620479909603 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2 + sha256: 00925c8c055a2275614b4d983e1df637245e19058d79fc7dd1a93b8d9fb4b139 + md5: 4d59c254e01d9cde7957100457e2d5fb + license: OFL-1.1 + license_family: Other + purls: [] + size: 700814 + timestamp: 1620479612257 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda + sha256: 2821ec1dc454bd8b9a31d0ed22a7ce22422c0aef163c59f49dfdf915d0f0ca14 + md5: 49023d73832ef61042f6a237cb2687e7 + license: LicenseRef-Ubuntu-Font-Licence-Version-1.0 + license_family: Other + purls: [] + size: 1620504 + timestamp: 1727511233259 +- conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.15.0-h7e30c49_1.conda + sha256: 7093aa19d6df5ccb6ca50329ef8510c6acb6b0d8001191909397368b65b02113 + md5: 8f5b0b297b59e1ac160ad4beec99dbee + depends: + - __glibc >=2.17,<3.0.a0 + - freetype >=2.12.1,<3.0a0 + - libexpat >=2.6.3,<3.0a0 + - libgcc >=13 + - libuuid >=2.38.1,<3.0a0 + - libzlib >=1.3.1,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 265599 + timestamp: 1730283881107 +- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2 + sha256: a997f2f1921bb9c9d76e6fa2f6b408b7fa549edd349a77639c9fe7a23ea93e61 + md5: fee5683a3f04bd15cbd8318b096a27ab + depends: + - fonts-conda-forge + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 3667 + timestamp: 1566974674465 +- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2 + sha256: 53f23a3319466053818540bcdf2091f253cbdbab1e0e9ae7b9e509dcaa2a5e38 + md5: f766549260d6815b0c52253f1fb1bb29 + depends: + - font-ttf-dejavu-sans-mono + - font-ttf-inconsolata + - font-ttf-source-code-pro + - font-ttf-ubuntu + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 4102 + timestamp: 1566932280397 +- conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.59.0-py312h8a5da7c_0.conda + sha256: ead830a4d12f26066f09b6ea54fb5c9e26a548c901063381412636db92cf7f61 + md5: 008d44a468c24a59d2e67c014fba8f12 + depends: + - __glibc >=2.17,<3.0.a0 + - brotli + - libgcc >=14 + - munkres + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + - unicodedata2 >=15.1.0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/fonttools?source=hash-mapping + size: 2854951 + timestamp: 1752723143 +- conda: https://conda.anaconda.org/conda-forge/linux-64/freetype-2.13.3-ha770c72_1.conda + sha256: 7ef7d477c43c12a5b4cddcf048a83277414512d1116aba62ebadfa7056a7d84f + md5: 9ccd736d31e0c6e41f54e704e5312811 + depends: + - libfreetype 2.13.3 ha770c72_1 + - libfreetype6 2.13.3 h48d6fc4_1 + license: GPL-2.0-only OR FTL + purls: [] + size: 172450 + timestamp: 1745369996765 - pypi: https://files.pythonhosted.org/packages/44/4b/e0cfc1a6f17e990f3e64b7d941ddc4acdc7b19d6edd51abf495f32b1a9e4/fsspec-2025.3.2-py3-none-any.whl name: fsspec version: 2025.3.2 @@ -679,6 +1248,23 @@ packages: - zstandard ; extra == 'test-full' - tqdm ; extra == 'tqdm' requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.14-hecca717_1.conda + sha256: 060dbb9e8f025cd09819586dd9c5a9c29bfcff0ac222435c90f4a83655caef7e + md5: d8f05f0493cacd0b29cbc0049669151f + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + license: LGPL-2.0-or-later + license_family: LGPL + purls: [] + size: 99475 + timestamp: 1754260291932 +- pypi: https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl + name: h11 + version: 0.16.0 + sha256: 63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86 + requires_python: '>=3.8' - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.2.0-pyhd8ed1ab_0.conda sha256: 0aa1cdc67a9fe75ea95b5644b734a756200d6ec9d0dff66530aec3d1c1e9df75 md5: b4754fb1bdcb70c8fd54f918301582c6 @@ -692,6 +1278,27 @@ packages: - pkg:pypi/h2?source=hash-mapping size: 53888 timestamp: 1738578623567 +- conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-11.2.1-h3beb420_0.conda + sha256: 5bd0f3674808862838d6e2efc0b3075e561c34309c5c2f4c976f7f1f57c91112 + md5: 0e6e192d4b3d95708ad192d957cf3163 + depends: + - __glibc >=2.17,<3.0.a0 + - cairo >=1.18.4,<2.0a0 + - freetype + - graphite2 + - icu >=75.1,<76.0a0 + - libexpat >=2.7.0,<3.0a0 + - libfreetype >=2.13.3 + - libfreetype6 >=2.13.3 + - libgcc >=13 + - libglib >=2.84.1,<3.0a0 + - libstdcxx >=13 + - libzlib >=1.3.1,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 1730226 + timestamp: 1747091044218 - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda sha256: 6ad78a180576c706aabeb5b4c8ceb97c0cb25f1e112d76495bff23e3779948ba md5: 0a802cb9888dd14eeefc611f05c40b6e @@ -703,6 +1310,36 @@ packages: - pkg:pypi/hpack?source=hash-mapping size: 30731 timestamp: 1737618390337 +- pypi: https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl + name: httpcore + version: 1.0.9 + sha256: 2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55 + requires_dist: + - certifi + - h11>=0.16 + - anyio>=4.0,<5.0 ; extra == 'asyncio' + - h2>=3,<5 ; extra == 'http2' + - socksio==1.* ; extra == 'socks' + - trio>=0.22.0,<1.0 ; extra == 'trio' + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl + name: httpx + version: 0.28.1 + sha256: d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad + requires_dist: + - anyio + - certifi + - httpcore==1.* + - idna + - brotli ; platform_python_implementation == 'CPython' and extra == 'brotli' + - brotlicffi ; platform_python_implementation != 'CPython' and extra == 'brotli' + - click==8.* ; extra == 'cli' + - pygments==2.* ; extra == 'cli' + - rich>=10,<14 ; extra == 'cli' + - h2>=3,<5 ; extra == 'http2' + - socksio==1.* ; extra == 'socks' + - zstandard>=0.18.0 ; extra == 'zstd' + requires_python: '>=3.8' - pypi: https://files.pythonhosted.org/packages/99/e3/2232d0e726d4d6ea69643b9593d97d0e7e6ea69c2fe9ed5de34d476c1c47/huggingface_hub-0.30.1-py3-none-any.whl name: huggingface-hub version: 0.30.1 @@ -825,6 +1462,18 @@ packages: - pkg:pypi/hyperframe?source=hash-mapping size: 17397 timestamp: 1737618427549 +- conda: https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda + sha256: 71e750d509f5fa3421087ba88ef9a7b9be11c53174af3aa4d06aff4c18b38e8e + md5: 8b189310083baabfb622af68fd9d3ae3 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc-ng >=12 + - libstdcxx-ng >=12 + license: MIT + license_family: MIT + purls: [] + size: 12129203 + timestamp: 1720853576813 - conda: https://conda.anaconda.org/conda-forge/noarch/id-1.5.0-pyh29332c3_0.conda sha256: 161e3eb5aba887d0329bb4099f72cb92eed9072cf63f551d08540480116e69a2 md5: d37314c8f553e3b4b44d113a0ee10196 @@ -838,6 +1487,18 @@ packages: - pkg:pypi/id?source=hash-mapping size: 24444 timestamp: 1737528654512 +- conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.12-pyhd8ed1ab_0.conda + sha256: 4debbae49a183d61f0747a5f594fca2bf5121e8508a52116f50ccd0eb2f7bb55 + md5: 84463b10c1eb198541cd54125c7efe90 + depends: + - python >=3.9 + - ukkonen + license: MIT + license_family: MIT + purls: + - pkg:pypi/identify?source=hash-mapping + size: 78926 + timestamp: 1748049754416 - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.10-pyhd8ed1ab_1.conda sha256: d7a472c9fd479e2e8dcb83fb8d433fce971ea369d704ece380e876f9c3494e87 md5: 39a4f67be3286c86d696df570b1201b7 @@ -875,6 +1536,17 @@ packages: - pkg:pypi/importlib-resources?source=hash-mapping size: 33781 timestamp: 1736252433366 +- conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda + sha256: 0ec8f4d02053cd03b0f3e63168316530949484f80e16f5e2fb199a1d117a89ca + md5: 6837f3eff7dcea42ecd714ce1ac2b108 + depends: + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/iniconfig?source=hash-mapping + size: 11474 + timestamp: 1733223232820 - pypi: https://files.pythonhosted.org/packages/20/3a/917cb9e72f4e1a4ea13c862533205ae1319bd664119189ee5cc9e4e95ebf/ipython-9.0.2-py3-none-any.whl name: ipython version: 9.0.2 @@ -1052,6 +1724,21 @@ packages: purls: [] size: 117831 timestamp: 1646151697040 +- conda: https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.8-py312h68727a3_1.conda + sha256: 34814cea4b92d17237211769f2ec5b739a328849b152a2f5736183c52d48cafc + md5: a8ea818e46addfa842348701a9dbe8f8 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libstdcxx >=13 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/kiwisolver?source=hash-mapping + size: 72166 + timestamp: 1751493973594 - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda sha256: 99df692f7a8a5c27cd14b5fb1374ee55e756631b9c3d659ed3ee60830249b238 md5: 3f43953b7d3fb3aaa1d0d0723d91e368 @@ -1067,6 +1754,19 @@ packages: purls: [] size: 1370023 timestamp: 1719463201255 +- conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.17-h717163a_0.conda + sha256: d6a61830a354da022eae93fa896d0991385a875c6bba53c82263a289deda9db8 + md5: 000e85703f0fd9594c81710dd5066471 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libjpeg-turbo >=3.0.0,<4.0a0 + - libtiff >=4.7.0,<4.8.0a0 + license: MIT + license_family: MIT + purls: [] + size: 248046 + timestamp: 1739160907615 - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_4.conda sha256: db73f38155d901a610b2320525b9dd3b31e4949215c870685fd92ea61b5ce472 md5: 01f8d123c96816249efd255a31ad7712 @@ -1079,6 +1779,126 @@ packages: purls: [] size: 671240 timestamp: 1740155456116 +- conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h0aef613_1.conda + sha256: 412381a43d5ff9bbed82cd52a0bbca5b90623f62e41007c9c42d3870c60945ff + md5: 9344155d33912347b37f0ae6c410a835 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libstdcxx >=13 + license: Apache-2.0 + license_family: Apache + purls: [] + size: 264243 + timestamp: 1745264221534 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-31_h59b9bed_openblas.conda + build_number: 31 + sha256: 9839fc4ac0cbb0aa3b9eea520adfb57311838959222654804e58f6f2d1771db5 + md5: 728dbebd0f7a20337218beacffd37916 + depends: + - libopenblas >=0.3.29,<0.3.30.0a0 + - libopenblas >=0.3.29,<1.0a0 + constrains: + - liblapacke =3.9.0=31*_openblas + - liblapack =3.9.0=31*_openblas + - blas =2.131=openblas + - mkl <2025 + - libcblas =3.9.0=31*_openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 16859 + timestamp: 1740087969120 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hb9d3cd8_2.conda + sha256: d9db2de60ea917298e658143354a530e9ca5f9c63471c65cf47ab39fd2f429e3 + md5: 41b599ed2b02abcfdd84302bff174b23 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 68851 + timestamp: 1725267660471 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.1.0-hb9d3cd8_2.conda + sha256: 2892d512cad096cb03f1b66361deeab58b64e15ba525d6592bb6d609e7045edf + md5: 9566f0bd264fbd463002e759b8a82401 + depends: + - __glibc >=2.17,<3.0.a0 + - libbrotlicommon 1.1.0 hb9d3cd8_2 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 32696 + timestamp: 1725267669305 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.1.0-hb9d3cd8_2.conda + sha256: 779f58174e99de3600e939fa46eddb453ec5d3c60bb46cdaa8b4c127224dbf29 + md5: 06f70867945ea6a84d35836af780f1de + depends: + - __glibc >=2.17,<3.0.a0 + - libbrotlicommon 1.1.0 hb9d3cd8_2 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 281750 + timestamp: 1725267679782 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-31_he106b2a_openblas.conda + build_number: 31 + sha256: ede8545011f5b208b151fe3e883eb4e31d495ab925ab7b9ce394edca846e0c0d + md5: abb32c727da370c481a1c206f5159ce9 + depends: + - libblas 3.9.0 31_h59b9bed_openblas + constrains: + - liblapacke =3.9.0=31*_openblas + - liblapack =3.9.0=31*_openblas + - blas =2.131=openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 16796 + timestamp: 1740087984429 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp20.1-20.1.4-default_h1df26ce_0.conda + sha256: 5c28304eaabc2aaeb47e2ba847ae41e0ad7e2a520a7e19a2c5e846c69b417a5b + md5: 96f8d5b2e94c9ba4fef19f1adf068a15 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libllvm20 >=20.1.4,<20.2.0a0 + - libstdcxx >=13 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 20897372 + timestamp: 1746074729385 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libclang13-20.1.4-default_he06ed0a_0.conda + sha256: bdcfeb2dde582bec466f86c1fb1f8cbbd413653f60c030040fe1c842fc6da1b4 + md5: 2d933632c8004be47deb2be61bf013be + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libllvm20 >=20.1.4,<20.2.0a0 + - libstdcxx >=13 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 12096222 + timestamp: 1746074937700 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-hb8b1518_5.conda + sha256: cb83980c57e311783ee831832eb2c20ecb41e7dee6e86e8b70b8cef0e43eab55 + md5: d4a250da4737ee127fb1fa6452a9002e + depends: + - __glibc >=2.17,<3.0.a0 + - krb5 >=1.21.3,<1.22.0a0 + - libgcc >=13 + - libstdcxx >=13 + - libzlib >=1.3.1,<2.0a0 + license: Apache-2.0 + license_family: Apache + purls: [] + size: 4523621 + timestamp: 1749905341688 - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.13.0-h332b0f4_0.conda sha256: 38e528acfaa0276b7052f4de44271ff9293fdb84579650601a8c49dac171482a md5: cbdc92ac0d93fe3c796e36ad65c7905c @@ -1096,6 +1916,29 @@ packages: purls: [] size: 438088 timestamp: 1743601695669 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.23-h86f0d12_0.conda + sha256: 4db2f70a1441317d964e84c268e388110ad9cf75ca98994d1336d670e62e6f07 + md5: 27fe770decaf469a53f3e3a6d593067f + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 72783 + timestamp: 1745260463421 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.125-hb9d3cd8_0.conda + sha256: f53458db897b93b4a81a6dbfd7915ed8fa4a54951f97c698dde6faa028aadfd2 + md5: 4c0ab57463117fbb8df85268415082f5 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libpciaccess >=0.18,<0.19.0a0 + license: MIT + license_family: MIT + purls: [] + size: 246161 + timestamp: 1749904704373 - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda sha256: d789471216e7aba3c184cd054ed61ce3f6dac6f87a50ec69291b9297f8c18724 md5: c277e0a4d549b03ac1e9d6cbbe3d017b @@ -1109,6 +1952,16 @@ packages: purls: [] size: 134676 timestamp: 1738479519902 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_2.conda + sha256: 7fd5408d359d05a969133e47af580183fbf38e2235b562193d427bb9dad79723 + md5: c151d5eb730e9b7480e6d48c0fc44048 + depends: + - __glibc >=2.17,<3.0.a0 + - libglvnd 1.7.0 ha4b6fd6_2 + license: LicenseRef-libglvnd + purls: [] + size: 44840 + timestamp: 1731330973553 - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda sha256: 1cd6048169fa0395af74ed5d8f1716e22c19a81a8a36f934c110ca3ad4dd27b4 md5: 172bf1cd1ff8629f2b1179945ed45055 @@ -1141,8 +1994,31 @@ packages: license: MIT license_family: MIT purls: [] - size: 57433 - timestamp: 1743434498161 + size: 57433 + timestamp: 1743434498161 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.13.3-ha770c72_1.conda + sha256: 7be9b3dac469fe3c6146ff24398b685804dfc7a1de37607b84abd076f57cc115 + md5: 51f5be229d83ecd401fb369ab96ae669 + depends: + - libfreetype6 >=2.13.3 + license: GPL-2.0-only OR FTL + purls: [] + size: 7693 + timestamp: 1745369988361 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.13.3-h48d6fc4_1.conda + sha256: 7759bd5c31efe5fbc36a7a1f8ca5244c2eabdbeb8fc1bee4b99cf989f35c7d81 + md5: 3c255be50a506c50765a93a6644f32fe + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libpng >=1.6.47,<1.7.0a0 + - libzlib >=1.3.1,<2.0a0 + constrains: + - freetype >=2.13.3 + license: GPL-2.0-only OR FTL + purls: [] + size: 380134 + timestamp: 1745369987697 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h767d61c_2.conda sha256: 3a572d031cb86deb541d15c1875aaa097baefc0c580b54dc61f5edab99215792 md5: ef504d1acbd74b7cc6849ef8af47dd03 @@ -1167,22 +2043,78 @@ packages: purls: [] size: 53758 timestamp: 1740240660904 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.84.0-h2ff4ddf_0.conda - sha256: 8e8737ca776d897d81a97e3de28c4bb33c45b5877bbe202b9b0ad2f61ca39397 - md5: 40cdeafb789a5513415f7bdbef053cf5 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-14.2.0-h69a702a_2.conda + sha256: e05263e8960da03c341650f2a3ffa4ccae4e111cb198e8933a2908125459e5a6 + md5: fb54c4ea68b460c278d26eea89cfbcc3 + depends: + - libgfortran5 14.2.0 hf1ad2bd_2 + constrains: + - libgfortran-ng ==14.2.0=*_2 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 53733 + timestamp: 1740240690977 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.2.0-hf1ad2bd_2.conda + sha256: c17b7cf3073a1f4e1f34d50872934fa326346e104d3c445abc1e62481ad6085c + md5: 556a4fdfac7287d349b8f09aba899693 depends: - __glibc >=2.17,<3.0.a0 - - libffi >=3.4,<4.0a0 + - libgcc >=14.2.0 + constrains: + - libgfortran 14.2.0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 1461978 + timestamp: 1740240671964 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_2.conda + sha256: dc2752241fa3d9e40ce552c1942d0a4b5eeb93740c9723873f6fcf8d39ef8d2d + md5: 928b8be80851f5d8ffb016f9c81dae7a + depends: + - __glibc >=2.17,<3.0.a0 + - libglvnd 1.7.0 ha4b6fd6_2 + - libglx 1.7.0 ha4b6fd6_2 + license: LicenseRef-libglvnd + purls: [] + size: 134712 + timestamp: 1731330998354 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.84.1-h2ff4ddf_0.conda + sha256: 18e354d30a60441b0bf5fcbb125b6b22fd0df179620ae834e2533d44d1598211 + md5: 0305434da649d4fb48a425e588b79ea6 + depends: + - __glibc >=2.17,<3.0.a0 + - libffi >=3.4.6,<3.5.0a0 - libgcc >=13 - libiconv >=1.18,<2.0a0 - libzlib >=1.3.1,<2.0a0 - pcre2 >=10.44,<10.45.0a0 constrains: - - glib 2.84.0 *_0 + - glib 2.84.1 *_0 license: LGPL-2.1-or-later purls: [] - size: 3998765 - timestamp: 1743038881905 + size: 3947789 + timestamp: 1743773764878 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda + sha256: 1175f8a7a0c68b7f81962699751bb6574e6f07db4c9f72825f978e3016f46850 + md5: 434ca7e50e40f4918ab701e3facd59a0 + depends: + - __glibc >=2.17,<3.0.a0 + license: LicenseRef-libglvnd + purls: [] + size: 132463 + timestamp: 1731330968309 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_2.conda + sha256: 2d35a679624a93ce5b3e9dd301fff92343db609b79f0363e6d0ceb3a6478bfa7 + md5: c8013e438185f33b13814c5c488acd5c + depends: + - __glibc >=2.17,<3.0.a0 + - libglvnd 1.7.0 ha4b6fd6_2 + - xorg-libx11 >=1.8.10,<2.0a0 + license: LicenseRef-libglvnd + purls: [] + size: 75504 + timestamp: 1731330988898 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.2.0-h767d61c_2.conda sha256: 1a3130e0b9267e781b89399580f3163632d59fe5b0142900d63052ab1a53490e md5: 06d02030237f4d5b3d9a7e7d348fe3c6 @@ -1203,6 +2135,48 @@ packages: purls: [] size: 713084 timestamp: 1740128065462 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.0-hb9d3cd8_0.conda + sha256: 98b399287e27768bf79d48faba8a99a2289748c65cd342ca21033fab1860d4a4 + md5: 9fa334557db9f63da6c9285fd2a48638 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + constrains: + - jpeg <0.0.0a + license: IJG AND BSD-3-Clause AND Zlib + purls: [] + size: 628947 + timestamp: 1745268527144 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-31_h7ac8fdf_openblas.conda + build_number: 31 + sha256: f583661921456e798aba10972a8abbd9d33571c655c1f66eff450edc9cbefcf3 + md5: 452b98eafe050ecff932f0ec832dd03f + depends: + - libblas 3.9.0 31_h59b9bed_openblas + constrains: + - libcblas =3.9.0=31*_openblas + - liblapacke =3.9.0=31*_openblas + - blas =2.131=openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 16790 + timestamp: 1740087997375 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm20-20.1.4-he9d0ab4_0.conda + sha256: 56a375dc36df1a4e2061e30ebbacbc9599a11277422a9a3145fd228f772bab53 + md5: 96c33bbd084ef2b2463503fb7f1482ae + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libstdcxx >=13 + - libxml2 >=2.13.7,<2.14.0a0 + - libzlib >=1.3.1,<2.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 43004201 + timestamp: 1746052658083 - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.6.4-hb9d3cd8_0.conda sha256: cad52e10319ca4585bc37f0bc7cce99ec7c15dc9168e42ccb96b741b0a27db3f md5: 42d5b6a0f30d3c10cd88cb8584fda1cb @@ -1240,6 +2214,77 @@ packages: purls: [] size: 33408 timestamp: 1697359010159 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.8-hb9d3cd8_0.conda + sha256: 3b3f19ced060013c2dd99d9d46403be6d319d4601814c772a3472fe2955612b0 + md5: 7c7927b404672409d9917d49bff5f2d6 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: LGPL-2.1-or-later + purls: [] + size: 33418 + timestamp: 1734670021371 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.29-pthreads_h94d23a6_0.conda + sha256: cc5389ea254f111ef17a53df75e8e5209ef2ea6117e3f8aced88b5a8e51f11c4 + md5: 0a4d0252248ef9a0f88f2ba8b8a08e12 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libgfortran + - libgfortran5 >=14.2.0 + constrains: + - openblas >=0.3.29,<0.3.30.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 5919288 + timestamp: 1739825731827 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_2.conda + sha256: 215086c108d80349e96051ad14131b751d17af3ed2cb5a34edd62fa89bfe8ead + md5: 7df50d44d4a14d6c31a2c54f2cd92157 + depends: + - __glibc >=2.17,<3.0.a0 + - libglvnd 1.7.0 ha4b6fd6_2 + license: LicenseRef-libglvnd + purls: [] + size: 50757 + timestamp: 1731330993524 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hb9d3cd8_0.conda + sha256: 0bd91de9b447a2991e666f284ae8c722ffb1d84acb594dbd0c031bd656fa32b2 + md5: 70e3400cbbfa03e96dcde7fc13e38c7b + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 28424 + timestamp: 1749901812541 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.50-h421ea60_1.conda + sha256: e75a2723000ce3a4b9fd9b9b9ce77553556c93e475a4657db6ed01abc02ea347 + md5: 7af8e91b0deb5f8e25d1a595dea79614 + depends: + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - libzlib >=1.3.1,<2.0a0 + license: zlib-acknowledgement + purls: [] + size: 317390 + timestamp: 1753879899951 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libpq-17.4-h27ae623_1.conda + sha256: ba2fd74be9d8c38489b9c6c18fa2fa87437dac76dfe285f86425c1b815e59fa2 + md5: 37fba334855ef3b51549308e61ed7a3d + depends: + - __glibc >=2.17,<3.0.a0 + - icu >=75.1,<76.0a0 + - krb5 >=1.21.3,<1.22.0a0 + - libgcc >=13 + - openldap >=2.6.9,<2.7.0a0 + - openssl >=3.4.1,<4.0a0 + license: PostgreSQL + purls: [] + size: 2736307 + timestamp: 1743504522214 - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.49.1-hee588c1_2.conda sha256: a086289bf75c33adc1daed3f1422024504ffb5c3c8b3285c49f025c29708ed16 md5: 962d6ac93c30b1dfc54c9cccafd1003e @@ -1285,6 +2330,24 @@ packages: purls: [] size: 53830 timestamp: 1740240722530 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.0-hd9ff511_3.conda + sha256: b224e16b88d76ea95e4af56e2bc638c603bd26a770b98d117d04541d3aafa002 + md5: 0ea6510969e1296cc19966fad481f6de + depends: + - __glibc >=2.17,<3.0.a0 + - lerc >=4.0.0,<5.0a0 + - libdeflate >=1.23,<1.24.0a0 + - libgcc >=13 + - libjpeg-turbo >=3.0.0,<4.0a0 + - liblzma >=5.6.3,<6.0a0 + - libstdcxx >=13 + - libwebp-base >=1.4.0,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - zstd >=1.5.6,<1.6.0a0 + license: HPND + purls: [] + size: 428173 + timestamp: 1734398813264 - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda sha256: 787eb542f055a2b3de553614b25f09eefb0a0931b0c87dbcce6efdfd92f04f18 md5: 40b61aab5c7ba9ff276c41cfffe6b80b @@ -1306,6 +2369,33 @@ packages: purls: [] size: 891272 timestamp: 1737016632446 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda + sha256: 3aed21ab28eddffdaf7f804f49be7a7d701e8f0e46c856d801270b470820a37b + md5: aea31d2e5b1091feca96fcfe945c3cf9 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + constrains: + - libwebp 1.6.0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 429011 + timestamp: 1752159441324 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda + sha256: 666c0c431b23c6cec6e492840b176dde533d48b7e6fb8883f5071223433776aa + md5: 92ed62436b625154323d40d5f2f11dd7 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - pthread-stubs + - xorg-libxau >=1.0.11,<2.0a0 + - xorg-libxdmcp + license: MIT + license_family: MIT + purls: [] + size: 395888 + timestamp: 1727278577118 - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda sha256: 6ae68e0b86423ef188196fff6207ed0c8195dd84273cb5623b85aa08033a410c md5: 5aa797f8787fe7a17d1b0821485b5adc @@ -1315,6 +2405,48 @@ packages: purls: [] size: 100393 timestamp: 1702724383534 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.9.2-h65c71a3_0.conda + sha256: 49bbeb112b3242f49e4bb1ac8af2d08c447bf3929b475915d67f02628643ed55 + md5: d045b1d878031eb497cab44e6392b1df + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libstdcxx >=13 + - libxcb >=1.17.0,<2.0a0 + - libxml2 >=2.13.7,<2.14.0a0 + - xkeyboard-config + - xorg-libxau >=1.0.12,<2.0a0 + license: MIT/X11 Derivative + license_family: MIT + purls: [] + size: 675947 + timestamp: 1746581272970 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.7-h8d12d68_0.conda + sha256: 98f0a11d6b52801daaeefd00bfb38078f439554d64d2e277d92f658faefac366 + md5: 109427e5576d0ce9c42257c2421b1680 + depends: + - __glibc >=2.17,<3.0.a0 + - icu >=75.1,<76.0a0 + - libgcc >=13 + - libiconv >=1.18,<2.0a0 + - liblzma >=5.6.4,<6.0a0 + - libzlib >=1.3.1,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 691755 + timestamp: 1743091084063 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.39-h76b75d6_0.conda + sha256: 684e9b67ef7b9ca0ca993762eeb39705ec58e2e7f958555c758da7ef416db9f3 + md5: e71f31f8cfb0a91439f2086fc8aa0461 + depends: + - libgcc-ng >=12 + - libxml2 >=2.12.1,<2.14.0a0 + license: MIT + license_family: MIT + purls: [] + size: 254297 + timestamp: 1701628814990 - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda sha256: d4bfe88d7cb447768e31650f06257995601f89076080e76df55e3112d4e47dc4 md5: edb0dca6bc32e4f4789199455a1dbeb8 @@ -1345,6 +2477,51 @@ packages: version: 3.0.2 sha256: e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8 requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.10.5-py312h7900ff3_0.conda + sha256: 34202064bc5a358ebbf561306dd259fd220ee22b14958f62d4990886f26db44a + md5: 32511cef24b61a6e955417060d3812c5 + depends: + - matplotlib-base >=3.10.5,<3.10.6.0a0 + - pyside6 >=6.7.2 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + - tornado >=5 + license: PSF-2.0 + license_family: PSF + purls: + - pkg:pypi/matplotlib?source=compressed-mapping + size: 17348 + timestamp: 1754005897072 +- conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.5-py312he3d6523_0.conda + sha256: 66e94e6226fd3dd04bb89d04079e2d8e2c74d923c0bbf255e483f127aee621ff + md5: 9246288e5ef2a944f7c9c648f9f331c7 + depends: + - __glibc >=2.17,<3.0.a0 + - contourpy >=1.0.1 + - cycler >=0.10 + - fonttools >=4.22.0 + - freetype + - kiwisolver >=1.3.1 + - libfreetype >=2.13.3 + - libfreetype6 >=2.13.3 + - libgcc >=14 + - libstdcxx >=14 + - numpy >=1.23 + - numpy >=1.23,<3 + - packaging >=20.0 + - pillow >=8 + - pyparsing >=2.3.1 + - python >=3.12,<3.13.0a0 + - python-dateutil >=2.7 + - python_abi 3.12.* *_cp312 + - qhull >=2020.2,<2020.3.0a0 + - tk >=8.6.13,<8.7.0a0 + license: PSF-2.0 + license_family: PSF + purls: + - pkg:pypi/matplotlib?source=compressed-mapping + size: 8071030 + timestamp: 1754005868258 - pypi: https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl name: matplotlib-inline version: 0.1.7 @@ -1399,6 +2576,46 @@ packages: requires_dist: - numpy>=1.9.0 - msgpack>=0.5.2 +- conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda + sha256: d09c47c2cf456de5c09fa66d2c3c5035aa1fa228a1983a433c47b876aa16ce90 + md5: 37293a85a0f4f77bbd9cf7aaefc62609 + depends: + - python >=3.9 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/munkres?source=hash-mapping + size: 15851 + timestamp: 1749895533014 +- conda: https://conda.anaconda.org/conda-forge/linux-64/mysql-common-9.0.1-h266115a_6.conda + sha256: 9c2e3f9e9883e4b8d7e9e6abf7b235dc00bdcd5ef66640a360464a9f5756294d + md5: 94116b69829e90b72d566e64421e1bff + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libstdcxx >=13 + - openssl >=3.4.1,<4.0a0 + license: GPL-2.0-or-later + license_family: GPL + purls: [] + size: 616215 + timestamp: 1744124836761 +- conda: https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-9.0.1-he0572af_6.conda + sha256: 274467a602944d12722f757f660ad034de6f5f5d7d2ea1b913ef6fd836c1b8ce + md5: 9802ae6d20982f42c0f5d69008988763 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libstdcxx >=13 + - libzlib >=1.3.1,<2.0a0 + - mysql-common 9.0.1 h266115a_6 + - openssl >=3.4.1,<4.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: GPL-2.0-or-later + license_family: GPL + purls: [] + size: 1369369 + timestamp: 1744124916632 - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda sha256: 3fde293232fa3fca98635e1167de6b7c7fda83caf24b9d6c91ec9eefb4f4d586 md5: 47e340acb35de30501a76c7c799c41d7 @@ -1462,11 +2679,39 @@ packages: - pkg:pypi/nh3?source=hash-mapping size: 621078 timestamp: 1741652643562 -- pypi: https://files.pythonhosted.org/packages/02/e2/e2cbb8d634151aab9528ef7b8bab52ee4ab10e076509285602c2a3a686e0/numpy-2.2.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - name: numpy - version: 2.2.4 - sha256: 4f92084defa704deadd4e0a5ab1dc52d8ac9e8a8ef617f3fbb853e79b0ea3592 - requires_python: '>=3.10' +- conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.9.1-pyhd8ed1ab_1.conda + sha256: 3636eec0e60466a00069b47ce94b6d88b01419b6577d8e393da44bb5bc8d3468 + md5: 7ba3f09fceae6a120d664217e58fe686 + depends: + - python >=3.9 + - setuptools + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/nodeenv?source=hash-mapping + size: 34574 + timestamp: 1734112236147 +- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.3.2-py312h33ff503_0.conda + sha256: d54e52df67e0be7e5faa9e6f0efccea3d72f635a3159cc151c4668e5159f6ef3 + md5: 3f6efbc40eb13f019c856c410fa921d2 + depends: + - python + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - libstdcxx >=14 + - libgcc >=14 + - libblas >=3.9.0,<4.0a0 + - python_abi 3.12.* *_cp312 + - libcblas >=3.9.0,<4.0a0 + - liblapack >=3.9.0,<4.0a0 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/numpy?source=compressed-mapping + size: 8785045 + timestamp: 1753401550884 - pypi: https://files.pythonhosted.org/packages/ae/71/1c91302526c45ab494c23f61c7a84aa568b8c1f9d196efa5993957faf906/nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_x86_64.whl name: nvidia-cublas-cu12 version: 12.4.5.8 @@ -1539,6 +2784,36 @@ packages: version: 12.4.127 sha256: 781e950d9b9f60d8241ccea575b32f5105a5baf4c2351cab5256a24869f12a1a requires_python: '>=3' +- conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.3-h55fea9a_1.conda + sha256: 0b7396dacf988f0b859798711b26b6bc9c6161dca21bacfd778473da58730afa + md5: 01243c4aaf71bde0297966125aea4706 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libpng >=1.6.50,<1.7.0a0 + - libstdcxx >=14 + - libtiff >=4.7.0,<4.8.0a0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 357828 + timestamp: 1754297886899 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.9-he970967_0.conda + sha256: 224f458848f792fe9e3587ee6b626d4eaad63aead0e5e6c25cbe29aba7b05c53 + md5: ca2de8bbdc871bce41dbf59e51324165 + depends: + - __glibc >=2.17,<3.0.a0 + - cyrus-sasl >=2.1.27,<3.0a0 + - krb5 >=1.21.3,<1.22.0a0 + - libgcc >=13 + - libstdcxx >=13 + - openssl >=3.4.0,<4.0a0 + license: OLDAP-2.8 + license_family: BSD + purls: [] + size: 784483 + timestamp: 1732674189726 - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.1-h7b32b05_0.conda sha256: cbf62df3c79a5c2d113247ddea5658e9ff3697b6e741c210656e239ecaf1768f md5: 41adf927e746dc75ecf0ef841c454e48 @@ -1562,97 +2837,58 @@ packages: - pkg:pypi/packaging?source=hash-mapping size: 60164 timestamp: 1733203368787 -- pypi: https://files.pythonhosted.org/packages/38/f8/d8fddee9ed0d0c0f4a2132c1dfcf0e3e53265055da8df952a53e7eaf178c/pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - name: pandas - version: 2.2.3 - sha256: fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319 - requires_dist: - - numpy>=1.22.4 ; python_full_version < '3.11' - - numpy>=1.23.2 ; python_full_version == '3.11.*' - - numpy>=1.26.0 ; python_full_version >= '3.12' - - python-dateutil>=2.8.2 - - pytz>=2020.1 - - tzdata>=2022.7 - - hypothesis>=6.46.1 ; extra == 'test' - - pytest>=7.3.2 ; extra == 'test' - - pytest-xdist>=2.2.0 ; extra == 'test' - - pyarrow>=10.0.1 ; extra == 'pyarrow' - - bottleneck>=1.3.6 ; extra == 'performance' - - numba>=0.56.4 ; extra == 'performance' - - numexpr>=2.8.4 ; extra == 'performance' - - scipy>=1.10.0 ; extra == 'computation' - - xarray>=2022.12.0 ; extra == 'computation' - - fsspec>=2022.11.0 ; extra == 'fss' - - s3fs>=2022.11.0 ; extra == 'aws' - - gcsfs>=2022.11.0 ; extra == 'gcp' - - pandas-gbq>=0.19.0 ; extra == 'gcp' - - odfpy>=1.4.1 ; extra == 'excel' - - openpyxl>=3.1.0 ; extra == 'excel' - - python-calamine>=0.1.7 ; extra == 'excel' - - pyxlsb>=1.0.10 ; extra == 'excel' - - xlrd>=2.0.1 ; extra == 'excel' - - xlsxwriter>=3.0.5 ; extra == 'excel' - - pyarrow>=10.0.1 ; extra == 'parquet' - - pyarrow>=10.0.1 ; extra == 'feather' - - tables>=3.8.0 ; extra == 'hdf5' - - pyreadstat>=1.2.0 ; extra == 'spss' - - sqlalchemy>=2.0.0 ; extra == 'postgresql' - - psycopg2>=2.9.6 ; extra == 'postgresql' - - adbc-driver-postgresql>=0.8.0 ; extra == 'postgresql' - - sqlalchemy>=2.0.0 ; extra == 'mysql' - - pymysql>=1.0.2 ; extra == 'mysql' - - sqlalchemy>=2.0.0 ; extra == 'sql-other' - - adbc-driver-postgresql>=0.8.0 ; extra == 'sql-other' - - adbc-driver-sqlite>=0.8.0 ; extra == 'sql-other' - - beautifulsoup4>=4.11.2 ; extra == 'html' - - html5lib>=1.1 ; extra == 'html' - - lxml>=4.9.2 ; extra == 'html' - - lxml>=4.9.2 ; extra == 'xml' - - matplotlib>=3.6.3 ; extra == 'plot' - - jinja2>=3.1.2 ; extra == 'output-formatting' - - tabulate>=0.9.0 ; extra == 'output-formatting' - - pyqt5>=5.15.9 ; extra == 'clipboard' - - qtpy>=2.3.0 ; extra == 'clipboard' - - zstandard>=0.19.0 ; extra == 'compression' - - dataframe-api-compat>=0.1.7 ; extra == 'consortium-standard' - - adbc-driver-postgresql>=0.8.0 ; extra == 'all' - - adbc-driver-sqlite>=0.8.0 ; extra == 'all' - - beautifulsoup4>=4.11.2 ; extra == 'all' - - bottleneck>=1.3.6 ; extra == 'all' - - dataframe-api-compat>=0.1.7 ; extra == 'all' - - fastparquet>=2022.12.0 ; extra == 'all' - - fsspec>=2022.11.0 ; extra == 'all' - - gcsfs>=2022.11.0 ; extra == 'all' - - html5lib>=1.1 ; extra == 'all' - - hypothesis>=6.46.1 ; extra == 'all' - - jinja2>=3.1.2 ; extra == 'all' - - lxml>=4.9.2 ; extra == 'all' - - matplotlib>=3.6.3 ; extra == 'all' - - numba>=0.56.4 ; extra == 'all' - - numexpr>=2.8.4 ; extra == 'all' - - odfpy>=1.4.1 ; extra == 'all' - - openpyxl>=3.1.0 ; extra == 'all' - - pandas-gbq>=0.19.0 ; extra == 'all' - - psycopg2>=2.9.6 ; extra == 'all' - - pyarrow>=10.0.1 ; extra == 'all' - - pymysql>=1.0.2 ; extra == 'all' - - pyqt5>=5.15.9 ; extra == 'all' - - pyreadstat>=1.2.0 ; extra == 'all' - - pytest>=7.3.2 ; extra == 'all' - - pytest-xdist>=2.2.0 ; extra == 'all' - - python-calamine>=0.1.7 ; extra == 'all' - - pyxlsb>=1.0.10 ; extra == 'all' - - qtpy>=2.3.0 ; extra == 'all' - - scipy>=1.10.0 ; extra == 'all' - - s3fs>=2022.11.0 ; extra == 'all' - - sqlalchemy>=2.0.0 ; extra == 'all' - - tables>=3.8.0 ; extra == 'all' - - tabulate>=0.9.0 ; extra == 'all' - - xarray>=2022.12.0 ; extra == 'all' - - xlrd>=2.0.1 ; extra == 'all' - - xlsxwriter>=3.0.5 ; extra == 'all' - - zstandard>=0.19.0 ; extra == 'all' - requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-2.3.1-py312hf79963d_0.conda + sha256: 6ec86b1da8432059707114270b9a45d767dac97c4910ba82b1f4fa6f74e077c8 + md5: 7c73e62e62e5864b8418440e2a2cc246 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + - numpy >=1.22.4 + - numpy >=1.23,<3 + - python >=3.12,<3.13.0a0 + - python-dateutil >=2.8.2 + - python-tzdata >=2022.7 + - python_abi 3.12.* *_cp312 + - pytz >=2020.1 + constrains: + - html5lib >=1.1 + - fastparquet >=2022.12.0 + - xarray >=2022.12.0 + - pyqt5 >=5.15.9 + - pyxlsb >=1.0.10 + - matplotlib >=3.6.3 + - numba >=0.56.4 + - odfpy >=1.4.1 + - bottleneck >=1.3.6 + - tabulate >=0.9.0 + - scipy >=1.10.0 + - pyreadstat >=1.2.0 + - pandas-gbq >=0.19.0 + - openpyxl >=3.1.0 + - xlrd >=2.0.1 + - pyarrow >=10.0.1 + - xlsxwriter >=3.0.5 + - python-calamine >=0.1.7 + - gcsfs >=2022.11.0 + - zstandard >=0.19.0 + - fsspec >=2022.11.0 + - lxml >=4.9.2 + - s3fs >=2022.11.0 + - numexpr >=2.8.4 + - psycopg2 >=2.9.6 + - qtpy >=2.3.0 + - pytables >=3.8.0 + - tzdata >=2022.7 + - sqlalchemy >=2.0.0 + - beautifulsoup4 >=4.11.2 + - blosc >=1.21.3 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/pandas?source=hash-mapping + size: 15092371 + timestamp: 1752082221274 - pypi: https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl name: parso version: 0.8.4 @@ -1664,6 +2900,18 @@ packages: - docopt ; extra == 'testing' - pytest ; extra == 'testing' requires_python: '>=3.6' +- conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.1-pyhd8ed1ab_1.conda + sha256: ab52916f056b435757d46d4ce0a93fd73af47df9c11fd72b74cc4b7e1caca563 + md5: ee23fabfd0a8c6b8d6f3729b47b2859d + depends: + - numpy >=1.4.0 + - python >=3.9 + license: BSD-2-Clause AND PSF-2.0 + license_family: BSD + purls: + - pkg:pypi/patsy?source=hash-mapping + size: 186594 + timestamp: 1733792482894 - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.44-hba22ea6_2.conda sha256: 1087716b399dab91cc9511d6499036ccdc53eb29a288bebcb19cf465c51d7c0d md5: df359c09c41cd186fffb93a2d87aa6f5 @@ -1683,33 +2931,29 @@ packages: sha256: 7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523 requires_dist: - ptyprocess>=0.5 -- pypi: https://files.pythonhosted.org/packages/38/0d/84200ed6a871ce386ddc82904bfadc0c6b28b0c0ec78176871a4679e40b3/pillow-11.1.0-cp312-cp312-manylinux_2_28_x86_64.whl - name: pillow - version: 11.1.0 - sha256: 9aa9aeddeed452b2f616ff5507459e7bab436916ccb10961c4a382cd3e03f47f - requires_dist: - - furo ; extra == 'docs' - - olefile ; extra == 'docs' - - sphinx>=8.1 ; extra == 'docs' - - sphinx-copybutton ; extra == 'docs' - - sphinx-inline-tabs ; extra == 'docs' - - sphinxext-opengraph ; extra == 'docs' - - olefile ; extra == 'fpx' - - olefile ; extra == 'mic' - - check-manifest ; extra == 'tests' - - coverage>=7.4.2 ; extra == 'tests' - - defusedxml ; extra == 'tests' - - markdown2 ; extra == 'tests' - - olefile ; extra == 'tests' - - packaging ; extra == 'tests' - - pyroma ; extra == 'tests' - - pytest ; extra == 'tests' - - pytest-cov ; extra == 'tests' - - pytest-timeout ; extra == 'tests' - - trove-classifiers>=2024.10.12 ; extra == 'tests' - - typing-extensions ; python_full_version < '3.10' and extra == 'typing' - - defusedxml ; extra == 'xmp' - requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-11.3.0-py312h80c1187_0.conda + sha256: 7c9a8f65a200587bf7a0135ca476f9c472348177338ed8b825ddcc08773fde68 + md5: 7911e727a6c24db662193a960b81b6b2 + depends: + - __glibc >=2.17,<3.0.a0 + - lcms2 >=2.17,<3.0a0 + - libfreetype >=2.13.3 + - libfreetype6 >=2.13.3 + - libgcc >=13 + - libjpeg-turbo >=3.1.0,<4.0a0 + - libtiff >=4.7.0,<4.8.0a0 + - libwebp-base >=1.5.0,<2.0a0 + - libxcb >=1.17.0,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - openjpeg >=2.5.3,<3.0a0 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + - tk >=8.6.13,<8.7.0a0 + license: HPND + purls: + - pkg:pypi/pillow?source=hash-mapping + size: 42964111 + timestamp: 1751482158083 - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.0.1-pyh8b19718_0.conda sha256: 585940f09d87787f79f73ff5dff8eb2af8a67e5bec5eebf2f553cd26c840ba69 md5: 79b5c1440aedc5010f687048d9103628 @@ -1723,6 +2967,18 @@ packages: - pkg:pypi/pip?source=hash-mapping size: 1256460 timestamp: 1739142857253 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h537e5f6_0.conda + sha256: f1a4bed536f8860b4e67fcd17662884dfa364e515c195c6d2e41dbf70f19263b + md5: b0674781beef9e302a17c330213ec41a + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + license: MIT + license_family: MIT + purls: [] + size: 410140 + timestamp: 1753105399719 - conda: https://conda.anaconda.org/conda-forge/linux-64/pkg-config-0.29.2-h4bc722e_1009.conda sha256: c9601efb1af5391317e04eca77c6fe4d716bf1ca1ad8da2a05d15cb7c28d7d4e md5: 1bee70681f504ea424fb07cdb090c001 @@ -1734,6 +2990,45 @@ packages: purls: [] size: 115175 timestamp: 1720805894943 +- conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.8-pyhe01879c_0.conda + sha256: 0f48999a28019c329cd3f6fd2f01f09fc32cc832f7d6bbe38087ddac858feaa3 + md5: 424844562f5d337077b445ec6b1398a7 + depends: + - python >=3.9 + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/platformdirs?source=hash-mapping + size: 23531 + timestamp: 1746710438805 +- conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + sha256: a8eb555eef5063bbb7ba06a379fa7ea714f57d9741fe0efdb9442dbbc2cccbcc + md5: 7da7ccd349dbf6487a7778579d2bb971 + depends: + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pluggy?source=hash-mapping + size: 24246 + timestamp: 1747339794916 +- conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.2.0-pyha770c72_0.conda + sha256: d0bd8cce5f31ae940934feedec107480c00f67e881bf7db9d50c6fc0216a2ee0 + md5: 17e487cc8b5507cd3abc09398cf27949 + depends: + - cfgv >=2.0.0 + - identify >=1.0.0 + - nodeenv >=0.11.1 + - python >=3.9 + - pyyaml >=5.1 + - virtualenv >=20.10.0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pre-commit?source=hash-mapping + size: 195854 + timestamp: 1742475656293 - pypi: https://files.pythonhosted.org/packages/e4/ea/d836f008d33151c7a1f62caf3d8dd782e4d15f6a43897f64480c2b8de2ad/prompt_toolkit-3.0.50-py3-none-any.whl name: prompt-toolkit version: 3.0.50 @@ -1741,6 +3036,17 @@ packages: requires_dist: - wcwidth requires_python: '>=3.8.0' +- conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda + sha256: 9c88f8c64590e9567c6c80823f0328e58d3b1efb0e1c539c0315ceca764e0973 + md5: b3c17d95b5a10c6e64a21fa17573e70e + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 8252 + timestamp: 1726802366959 - pypi: https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl name: ptyprocess version: 0.7.0 @@ -1759,7 +3065,8 @@ packages: - python license: BSD-3-Clause license_family: BSD - purls: [] + purls: + - pkg:pypi/pycparser?source=hash-mapping size: 110100 timestamp: 1733195786147 - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.1-pyhd8ed1ab_0.conda @@ -1773,6 +3080,42 @@ packages: - pkg:pypi/pygments?source=hash-mapping size: 888600 timestamp: 1736243563082 +- conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.3-pyhe01879c_2.conda + sha256: afe32182b1090911b64ac0f29eb47e03a015d142833d8a917defd65d91c99b74 + md5: aa0028616c0750c773698fdc254b2b8d + depends: + - python >=3.9 + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyparsing?source=compressed-mapping + size: 102292 + timestamp: 1753873557076 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.9.0-py312h91f0f75_0.conda + sha256: 4db931dccd8347140e79236378096d9a1b97b98bbd206d54cebd42491ad12535 + md5: e3a335c7530a1d0c4db621914f00f9f7 + depends: + - __glibc >=2.17,<3.0.a0 + - libclang13 >=20.1.2 + - libegl >=1.7.0,<2.0a0 + - libgcc >=13 + - libgl >=1.7.0,<2.0a0 + - libopengl >=1.7.0,<2.0a0 + - libstdcxx >=13 + - libxml2 >=2.13.7,<2.14.0a0 + - libxslt >=1.1.39,<2.0a0 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + - qt6-main 6.9.0.* + - qt6-main >=6.9.0,<6.10.0a0 + license: LGPL-3.0-only + license_family: LGPL + purls: + - pkg:pypi/pyside6?source=hash-mapping + - pkg:pypi/shiboken6?source=hash-mapping + size: 10119296 + timestamp: 1743760712824 - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda sha256: ba3b032fa52709ce0d9fd388f63d330a026754587a2f461117cac9ab73d8d0d8 md5: 461219d1a5bd61342293efa2c0c90eac @@ -1785,6 +3128,26 @@ packages: - pkg:pypi/pysocks?source=hash-mapping size: 21085 timestamp: 1733217331982 +- conda: https://conda.anaconda.org/conda-forge/noarch/pytest-8.4.1-pyhd8ed1ab_0.conda + sha256: 93e267e4ec35353e81df707938a6527d5eb55c97bf54c3b87229b69523afb59d + md5: a49c2283f24696a7b30367b7346a0144 + depends: + - colorama >=0.4 + - exceptiongroup >=1 + - iniconfig >=1 + - packaging >=20 + - pluggy >=1.5,<2 + - pygments >=2.7.2 + - python >=3.9 + - tomli >=1 + constrains: + - pytest-faulthandler >=2 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pytest?source=hash-mapping + size: 276562 + timestamp: 1750239526127 - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.9-h9e4cc4f_1_cpython.conda build_number: 1 sha256: 77f2073889d4c91a57bc0da73a0466d9164dbcf6191ea9c3a7be6872f784d625 @@ -1813,13 +3176,19 @@ packages: purls: [] size: 31670716 timestamp: 1741130026152 -- pypi: https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl - name: python-dateutil - version: 2.9.0.post0 - sha256: a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 - requires_dist: - - six>=1.5 - requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*' +- conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + sha256: d6a17ece93bbd5139e02d2bd7dbfa80bee1a4261dced63f65f679121686bf664 + md5: 5b8d21249ff20967101ffa321cab24e8 + depends: + - python >=3.9 + - six >=1.5 + - python + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/python-dateutil?source=hash-mapping + size: 233310 + timestamp: 1751104122689 - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.9-hd8ed1ab_1.conda sha256: d45a5a99ec3ad65d390590905c0d79b6223468d75425d988106473056ddc35e7 md5: a1a3aa64397603a81615400388409e10 @@ -1830,6 +3199,17 @@ packages: purls: [] size: 45697 timestamp: 1741128092145 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda + sha256: e8392a8044d56ad017c08fec2b0eb10ae3d1235ac967d0aab8bd7b41c4a5eaf0 + md5: 88476ae6ebd24f39261e0854ac244f33 + depends: + - python >=3.9 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/tzdata?source=hash-mapping + size: 144160 + timestamp: 1742745254292 - conda: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.12-6_cp312.conda build_number: 6 sha256: 09aff7ca31d1dbee63a504dba89aefa079b7c13a50dae18e1fe40a40ea71063e @@ -1841,15 +3221,105 @@ packages: purls: [] size: 6872 timestamp: 1743483197238 -- pypi: https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl - name: pytz - version: '2025.2' - sha256: 5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00 -- pypi: https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - name: pyyaml - version: 6.0.2 - sha256: 80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476 - requires_python: '>=3.8' +- conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda + sha256: 8d2a8bf110cc1fc3df6904091dead158ba3e614d8402a83e51ed3a8aa93cdeb0 + md5: bc8e3267d44011051f2eb14d22fb0960 + depends: + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pytz?source=hash-mapping + size: 189015 + timestamp: 1742920947249 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.2-py312h178313f_2.conda + sha256: 159cba13a93b3fe084a1eb9bda0a07afc9148147647f0d437c3c3da60980503b + md5: cf2485f39740de96e2a7f2bb18ed2fee + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyyaml?source=hash-mapping + size: 206903 + timestamp: 1737454910324 +- conda: https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda + sha256: 776363493bad83308ba30bcb88c2552632581b143e8ee25b1982c8c743e73abc + md5: 353823361b1d27eb3960efb076dfcaf6 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc-ng >=12 + - libstdcxx-ng >=12 + license: LicenseRef-Qhull + purls: [] + size: 552937 + timestamp: 1720813982144 +- conda: https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.9.0-h6441bc3_0.conda + sha256: 5f04a118f6f4124bf0f3a7b7ca2510954860c764db8c25a62bcfa91f51693073 + md5: d3df16592e15a3f833cfc4d19ae58677 + depends: + - __glibc >=2.17,<3.0.a0 + - alsa-lib >=1.2.13,<1.3.0a0 + - dbus >=1.13.6,<2.0a0 + - double-conversion >=3.3.1,<3.4.0a0 + - fontconfig >=2.15.0,<3.0a0 + - fonts-conda-ecosystem + - freetype >=2.13.3,<3.0a0 + - harfbuzz >=11.0.0,<12.0a0 + - icu >=75.1,<76.0a0 + - krb5 >=1.21.3,<1.22.0a0 + - libclang-cpp20.1 >=20.1.1,<20.2.0a0 + - libclang13 >=20.1.1 + - libcups >=2.3.3,<2.4.0a0 + - libdrm >=2.4.124,<2.5.0a0 + - libegl >=1.7.0,<2.0a0 + - libgcc >=13 + - libgl >=1.7.0,<2.0a0 + - libglib >=2.84.0,<3.0a0 + - libjpeg-turbo >=3.0.0,<4.0a0 + - libllvm20 >=20.1.1,<20.2.0a0 + - libpng >=1.6.47,<1.7.0a0 + - libpq >=17.4,<18.0a0 + - libsqlite >=3.49.1,<4.0a0 + - libstdcxx >=13 + - libtiff >=4.7.0,<4.8.0a0 + - libwebp-base >=1.5.0,<2.0a0 + - libxcb >=1.17.0,<2.0a0 + - libxkbcommon >=1.8.1,<2.0a0 + - libxml2 >=2.13.7,<2.14.0a0 + - libzlib >=1.3.1,<2.0a0 + - mysql-libs >=9.0.1,<9.1.0a0 + - openssl >=3.4.1,<4.0a0 + - pcre2 >=10.44,<10.45.0a0 + - wayland >=1.23.1,<2.0a0 + - xcb-util >=0.4.1,<0.5.0a0 + - xcb-util-cursor >=0.1.5,<0.2.0a0 + - xcb-util-image >=0.4.0,<0.5.0a0 + - xcb-util-keysyms >=0.4.1,<0.5.0a0 + - xcb-util-renderutil >=0.3.10,<0.4.0a0 + - xcb-util-wm >=0.4.2,<0.5.0a0 + - xorg-libice >=1.1.2,<2.0a0 + - xorg-libsm >=1.2.6,<2.0a0 + - xorg-libx11 >=1.8.12,<2.0a0 + - xorg-libxcomposite >=0.4.6,<1.0a0 + - xorg-libxcursor >=1.2.3,<2.0a0 + - xorg-libxdamage >=1.1.6,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + - xorg-libxrandr >=1.5.4,<2.0a0 + - xorg-libxtst >=1.2.5,<2.0a0 + - xorg-libxxf86vm >=1.1.6,<2.0a0 + - zstd >=1.5.7,<1.6.0a0 + constrains: + - qt 6.9.0 + license: LGPL-3.0-only + license_family: LGPL + purls: [] + size: 51884819 + timestamp: 1743632133306 - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8c095d6_2.conda sha256: 2d6d0c026902561ed77cd646b5021aef2d4db22e57a5b0178dfc669231e06d2c md5: 283b96675859b20a825f8fa30f311446 @@ -2048,49 +3518,58 @@ packages: - pooch>=1.6.0 ; extra == 'tests' - conda-lock==2.5.6 ; extra == 'maintenance' requires_python: '>=3.9' -- pypi: https://files.pythonhosted.org/packages/c0/53/eaada1a414c026673eb983f8b4a55fe5eb172725d33d62c1b21f63ff6ca4/scipy-1.15.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - name: scipy - version: 1.15.2 - sha256: 2b871df1fe1a3ba85d90e22742b93584f8d2b8e6124f8372ab15c71b73e428b8 - requires_dist: - - numpy>=1.23.5,<2.5 - - pytest ; extra == 'test' - - pytest-cov ; extra == 'test' - - pytest-timeout ; extra == 'test' - - pytest-xdist ; extra == 'test' - - asv ; extra == 'test' - - mpmath ; extra == 'test' - - gmpy2 ; extra == 'test' - - threadpoolctl ; extra == 'test' - - scikit-umfpack ; extra == 'test' - - pooch ; extra == 'test' - - hypothesis>=6.30 ; extra == 'test' - - array-api-strict>=2.0,<2.1.1 ; extra == 'test' - - cython ; extra == 'test' - - meson ; extra == 'test' - - ninja ; sys_platform != 'emscripten' and extra == 'test' - - sphinx>=5.0.0,<8.0.0 ; extra == 'doc' - - intersphinx-registry ; extra == 'doc' - - pydata-sphinx-theme>=0.15.2 ; extra == 'doc' - - sphinx-copybutton ; extra == 'doc' - - sphinx-design>=0.4.0 ; extra == 'doc' - - matplotlib>=3.5 ; extra == 'doc' - - numpydoc ; extra == 'doc' - - jupytext ; extra == 'doc' - - myst-nb ; extra == 'doc' - - pooch ; extra == 'doc' - - jupyterlite-sphinx>=0.16.5 ; extra == 'doc' - - jupyterlite-pyodide-kernel ; extra == 'doc' - - mypy==1.10.0 ; extra == 'dev' - - typing-extensions ; extra == 'dev' - - types-psutil ; extra == 'dev' - - pycodestyle ; extra == 'dev' - - ruff>=0.0.292 ; extra == 'dev' - - cython-lint>=0.12.2 ; extra == 'dev' - - rich-click ; extra == 'dev' - - doit>=0.36.0 ; extra == 'dev' - - pydevtool ; extra == 'dev' - requires_python: '>=3.10' +- conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.16.0-py312hf734454_0.conda + sha256: 8406e26bf853e699b1ea97792f63987808783ff4ab6ddeff9cf1ec0b9d1aa342 + md5: 7513ac56209d27a85ffa1582033f10a8 + depends: + - __glibc >=2.17,<3.0.a0 + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - libgcc >=13 + - libgfortran + - libgfortran5 >=13.3.0 + - liblapack >=3.9.0,<4.0a0 + - libstdcxx >=13 + - numpy <2.6 + - numpy >=1.23,<3 + - numpy >=1.25.2 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/scipy?source=hash-mapping + size: 16847456 + timestamp: 1751148548291 +- conda: https://conda.anaconda.org/conda-forge/noarch/seaborn-0.13.2-hd8ed1ab_3.conda + noarch: python + sha256: ea29a69b14dd6be5cdeeaa551bf50d78cafeaf0351e271e358f9b820fcab4cb0 + md5: 62afb877ca2c2b4b6f9ecb37320085b6 + depends: + - seaborn-base 0.13.2 pyhd8ed1ab_3 + - statsmodels >=0.12 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 6876 + timestamp: 1733730113224 +- conda: https://conda.anaconda.org/conda-forge/noarch/seaborn-base-0.13.2-pyhd8ed1ab_3.conda + sha256: f209c9c18187570b85ec06283c72d64b8738f825b1b82178f194f4866877f8aa + md5: fd96da444e81f9e6fcaac38590f3dd42 + depends: + - matplotlib-base >=3.4,!=3.6.1 + - numpy >=1.20,!=1.24.0 + - pandas >=1.2 + - python >=3.9 + - scipy >=1.7 + constrains: + - seaborn =0.13.2=*_3 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/seaborn?source=hash-mapping + size: 227843 + timestamp: 1733730112409 - conda: https://conda.anaconda.org/conda-forge/linux-64/secretstorage-3.3.3-py312h7900ff3_3.conda sha256: c6d5d0bc7fb6cbfa3b8be8f2399a3c1308b3392a4e20bd1a0f29a828fda5ab20 md5: 4840da9db2808db946a0d979603c6de4 @@ -2117,11 +3596,23 @@ packages: - pkg:pypi/setuptools?source=compressed-mapping size: 777736 timestamp: 1740654030775 -- pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl - name: six - version: 1.17.0 - sha256: 4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 - requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*' +- conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + sha256: 458227f759d5e3fcec5d9b7acce54e10c9e1f4f4b7ec978f3bfd54ce4ee9853d + md5: 3339e3b65d58accf4ca4fb8748ab16b3 + depends: + - python >=3.9 + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/six?source=compressed-mapping + size: 18455 + timestamp: 1753199211006 +- pypi: https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl + name: sniffio + version: 1.3.1 + sha256: 2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 + requires_python: '>=3.7' - pypi: https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl name: stack-data version: 0.6.3 @@ -2135,6 +3626,26 @@ packages: - pygments ; extra == 'tests' - littleutils ; extra == 'tests' - cython ; extra == 'tests' +- conda: https://conda.anaconda.org/conda-forge/linux-64/statsmodels-0.14.5-py312h8b63200_0.conda + sha256: 71af2d8efae963c83f9cd49f4648087d0acd41a58972a5bd7b097273b895ed54 + md5: d3588408248f78db333a5b019a4ca696 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - numpy <3,>=1.22.3 + - numpy >=1.23,<3 + - packaging >=21.3 + - pandas !=2.1.0,>=1.4 + - patsy >=0.5.6 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + - scipy !=1.9.2,>=1.8 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/statsmodels?source=hash-mapping + size: 12062670 + timestamp: 1751917720541 - pypi: https://files.pythonhosted.org/packages/b2/fe/81695a1aa331a842b582453b605175f419fe8540355886031328089d840a/sympy-1.13.1-py3-none-any.whl name: sympy version: 1.13.1 @@ -2188,6 +3699,18 @@ packages: - setuptools-rust ; extra == 'docs' - tokenizers[testing] ; extra == 'dev' requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.2.1-pyhe01879c_2.conda + sha256: 040a5a05c487647c089ad5e05ad5aff5942830db2a4e656f1e300d73436436f1 + md5: 30a0a26c8abccf4b7991d590fe17c699 + depends: + - python >=3.9 + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/tomli?source=compressed-mapping + size: 21238 + timestamp: 1753796677376 - pypi: https://files.pythonhosted.org/packages/e5/35/0c52d708144c2deb595cd22819a609f78fdd699b95ff6f0ebcd456e3c7c1/torch-2.6.0-cp312-cp312-manylinux1_x86_64.whl name: torch version: 2.6.0 @@ -2238,6 +3761,20 @@ packages: - gdown>=4.7.3 ; extra == 'gdown' - scipy ; extra == 'scipy' requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.1-py312h66e93f0_0.conda + sha256: c96be4c8bca2431d7ad7379bad94ed6d4d25cd725ae345540a531d9e26e148c9 + md5: c532a6ee766bed75c4fa0c39e959d132 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/tornado?source=hash-mapping + size: 850902 + timestamp: 1748003427956 - pypi: https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl name: tqdm version: 4.67.1 @@ -2689,11 +4226,6 @@ packages: - pkg:pypi/typing-extensions?source=hash-mapping size: 52077 timestamp: 1743201626659 -- pypi: https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl - name: tzdata - version: '2025.2' - sha256: 1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8 - requires_python: '>=2' - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda sha256: 5aaa366385d716557e365f0a4e9c3fca43ba196872abbbe3d56bb610d131e192 md5: 4222072737ccff51314b5ece9c7d6f5a @@ -2701,6 +4233,36 @@ packages: purls: [] size: 122968 timestamp: 1742727099393 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.0.1-py312h68727a3_5.conda + sha256: 9fb020083a7f4fee41f6ece0f4840f59739b3e249f157c8a407bb374ffb733b5 + md5: f9664ee31aed96c85b7319ab0a693341 + depends: + - __glibc >=2.17,<3.0.a0 + - cffi + - libgcc >=13 + - libstdcxx >=13 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ukkonen?source=hash-mapping + size: 13904 + timestamp: 1725784191021 +- conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-16.0.0-py312h66e93f0_0.conda + sha256: 638916105a836973593547ba5cf4891d1f2cb82d1cf14354fcef93fd5b941cdc + md5: 617f5d608ff8c28ad546e5d9671cbb95 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/unicodedata2?source=hash-mapping + size: 404401 + timestamp: 1736692621599 - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.3.0-pyhd8ed1ab_0.conda sha256: 114919ffa80c328127dab9c8e7a38f9d563c617691fb81fccb11c1e86763727e md5: 32674f8dbfb7b26410ed580dd3c10a29 @@ -2716,6 +4278,34 @@ packages: - pkg:pypi/urllib3?source=hash-mapping size: 100102 timestamp: 1734859520452 +- conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.33.1-pyhd8ed1ab_0.conda + sha256: 7b8328d79cb7ec19929ec955fe4dbb938d35da391a74a3974c47ca2622c64b04 + md5: 3f6ee060b1462c29b3442df71939a358 + depends: + - distlib >=0.3.7,<1 + - filelock >=3.12.2,<4 + - platformdirs >=3.9.1,<5 + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/virtualenv?source=compressed-mapping + size: 4138678 + timestamp: 1754419391413 +- conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.24.0-h3e06ad9_0.conda + sha256: ba673427dcd480cfa9bbc262fd04a9b1ad2ed59a159bd8f7e750d4c52282f34c + md5: 0f2ca7906bf166247d1d760c3422cb8a + depends: + - __glibc >=2.17,<3.0.a0 + - libexpat >=2.7.0,<3.0a0 + - libffi >=3.4.6,<3.5.0a0 + - libgcc >=13 + - libstdcxx >=13 + license: MIT + license_family: MIT + purls: [] + size: 330474 + timestamp: 1751817998141 - pypi: https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl name: wcwidth version: 0.2.13 @@ -2733,6 +4323,291 @@ packages: - pkg:pypi/wheel?source=hash-mapping size: 62931 timestamp: 1733130309598 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-h4f16b4b_2.conda + sha256: ad8cab7e07e2af268449c2ce855cbb51f43f4664936eff679b1f3862e6e4b01d + md5: fdc27cb255a7a2cc73b7919a968b48f0 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libxcb >=1.17.0,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 20772 + timestamp: 1750436796633 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-cursor-0.1.5-hb9d3cd8_0.conda + sha256: c7b35db96f6e32a9e5346f97adc968ef2f33948e3d7084295baebc0e33abdd5b + md5: eb44b3b6deb1cab08d72cb61686fe64c + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libxcb >=1.13 + - libxcb >=1.16,<2.0.0a0 + - xcb-util-image >=0.4.0,<0.5.0a0 + - xcb-util-renderutil >=0.3.10,<0.4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 20296 + timestamp: 1726125844850 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-hb711507_2.conda + sha256: 94b12ff8b30260d9de4fd7a28cca12e028e572cbc504fd42aa2646ec4a5bded7 + md5: a0901183f08b6c7107aab109733a3c91 + depends: + - libgcc-ng >=12 + - libxcb >=1.16,<2.0.0a0 + - xcb-util >=0.4.1,<0.5.0a0 + license: MIT + license_family: MIT + purls: [] + size: 24551 + timestamp: 1718880534789 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.1-hb711507_0.conda + sha256: 546e3ee01e95a4c884b6401284bb22da449a2f4daf508d038fdfa0712fe4cc69 + md5: ad748ccca349aec3e91743e08b5e2b50 + depends: + - libgcc-ng >=12 + - libxcb >=1.16,<2.0.0a0 + license: MIT + license_family: MIT + purls: [] + size: 14314 + timestamp: 1718846569232 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.10-hb711507_0.conda + sha256: 2d401dadc43855971ce008344a4b5bd804aca9487d8ebd83328592217daca3df + md5: 0e0cbe0564d03a99afd5fd7b362feecd + depends: + - libgcc-ng >=12 + - libxcb >=1.16,<2.0.0a0 + license: MIT + license_family: MIT + purls: [] + size: 16978 + timestamp: 1718848865819 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.2-hb711507_0.conda + sha256: 31d44f297ad87a1e6510895740325a635dd204556aa7e079194a0034cdd7e66a + md5: 608e0ef8256b81d04456e8d211eee3e8 + depends: + - libgcc-ng >=12 + - libxcb >=1.16,<2.0.0a0 + license: MIT + license_family: MIT + purls: [] + size: 51689 + timestamp: 1718844051451 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.45-hb9d3cd8_0.conda + sha256: a5d4af601f71805ec67403406e147c48d6bad7aaeae92b0622b7e2396842d3fe + md5: 397a013c2dc5145a70737871aaa87e98 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.12,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 392406 + timestamp: 1749375847832 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.2-hb9d3cd8_0.conda + sha256: c12396aabb21244c212e488bbdc4abcdef0b7404b15761d9329f5a4a39113c4b + md5: fb901ff28063514abb6046c9ec2c4a45 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 58628 + timestamp: 1734227592886 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.6-he73a12e_0.conda + sha256: 277841c43a39f738927145930ff963c5ce4c4dacf66637a3d95d802a64173250 + md5: 1c74ff8c35dcadf952a16f752ca5aa49 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libuuid >=2.38.1,<3.0a0 + - xorg-libice >=1.1.2,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 27590 + timestamp: 1741896361728 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.12-h4f16b4b_0.conda + sha256: 51909270b1a6c5474ed3978628b341b4d4472cd22610e5f22b506855a5e20f67 + md5: db038ce880f100acc74dba10302b5630 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libxcb >=1.17.0,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 835896 + timestamp: 1741901112627 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb9d3cd8_0.conda + sha256: ed10c9283974d311855ae08a16dfd7e56241fac632aec3b92e3cfe73cff31038 + md5: f6ebe2cb3f82ba6c057dde5d9debe4f7 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 14780 + timestamp: 1734229004433 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcomposite-0.4.6-hb9d3cd8_2.conda + sha256: 753f73e990c33366a91fd42cc17a3d19bb9444b9ca5ff983605fa9e953baf57f + md5: d3c295b50f092ab525ffe3c2aa4b7413 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-libxfixes >=6.0.1,<7.0a0 + license: MIT + license_family: MIT + purls: [] + size: 13603 + timestamp: 1727884600744 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcursor-1.2.3-hb9d3cd8_0.conda + sha256: 832f538ade441b1eee863c8c91af9e69b356cd3e9e1350fff4fe36cc573fc91a + md5: 2ccd714aa2242315acaf0a67faea780b + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-libxfixes >=6.0.1,<7.0a0 + - xorg-libxrender >=0.9.11,<0.10.0a0 + license: MIT + license_family: MIT + purls: [] + size: 32533 + timestamp: 1730908305254 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdamage-1.1.6-hb9d3cd8_0.conda + sha256: 43b9772fd6582bf401846642c4635c47a9b0e36ca08116b3ec3df36ab96e0ec0 + md5: b5fcc7172d22516e1f965490e65e33a4 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + - xorg-libxfixes >=6.0.1,<7.0a0 + license: MIT + license_family: MIT + purls: [] + size: 13217 + timestamp: 1727891438799 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb9d3cd8_0.conda + sha256: 6b250f3e59db07c2514057944a3ea2044d6a8cdde8a47b6497c254520fade1ee + md5: 8035c64cb77ed555e3f150b7b3972480 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 19901 + timestamp: 1727794976192 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.6-hb9d3cd8_0.conda + sha256: da5dc921c017c05f38a38bd75245017463104457b63a1ce633ed41f214159c14 + md5: febbab7d15033c913d53c7a2c102309d + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 50060 + timestamp: 1727752228921 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.1-hb9d3cd8_0.conda + sha256: 2fef37e660985794617716eb915865ce157004a4d567ed35ec16514960ae9271 + md5: 4bdb303603e9821baf5fe5fdff1dc8f8 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 19575 + timestamp: 1727794961233 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxi-1.8.2-hb9d3cd8_0.conda + sha256: 1a724b47d98d7880f26da40e45f01728e7638e6ec69f35a3e11f92acd05f9e7a + md5: 17dcc85db3c7886650b8908b183d6876 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + - xorg-libxfixes >=6.0.1,<7.0a0 + license: MIT + license_family: MIT + purls: [] + size: 47179 + timestamp: 1727799254088 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.4-hb9d3cd8_0.conda + sha256: ac0f037e0791a620a69980914a77cb6bb40308e26db11698029d6708f5aa8e0d + md5: 2de7f99d6581a4a7adbff607b5c278ca + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + - xorg-libxrender >=0.9.11,<0.10.0a0 + license: MIT + license_family: MIT + purls: [] + size: 29599 + timestamp: 1727794874300 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda + sha256: 044c7b3153c224c6cedd4484dd91b389d2d7fd9c776ad0f4a34f099b3389f4a1 + md5: 96d57aba173e878a2089d5638016dc5e + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 33005 + timestamp: 1734229037766 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxtst-1.2.5-hb9d3cd8_3.conda + sha256: 752fdaac5d58ed863bbf685bb6f98092fe1a488ea8ebb7ed7b606ccfce08637a + md5: 7bbe9a0cc0df0ac5f5a8ad6d6a11af2f + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + - xorg-libxi >=1.7.10,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 32808 + timestamp: 1727964811275 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.6-hb9d3cd8_0.conda + sha256: 8a4e2ee642f884e6b78c20c0892b85dd9b2a6e64a6044e903297e616be6ca35b + md5: 5efa5fa6243a622445fdfd72aee15efa + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 17819 + timestamp: 1734214575628 +- conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda + sha256: 6d9ea2f731e284e9316d95fa61869fe7bbba33df7929f82693c121022810f4ad + md5: a77f85f77be52ff59391544bfe73390a + depends: + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + license: MIT + license_family: MIT + purls: [] + size: 85189 + timestamp: 1753484064210 - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.21.0-pyhd8ed1ab_1.conda sha256: 567c04f124525c97a096b65769834b7acb047db24b15a56888a322bf3966c3e1 md5: 0c3cc595284c5e8f0f9900a9b228a332 diff --git a/pyproject.toml b/pyproject.toml index 081583af..715e55ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,6 +35,7 @@ dependencies = [ "attrs", "pandas", "cloudpathlib", + "httpx", "tenacity", "zstd" ] @@ -69,12 +70,14 @@ build-wheel = "python -m pip wheel --no-deps -w dist ." upload-wheel = "python -m twine upload --repository pypi" [tool.pixi.feature.dev.dependencies] -pytest = "*" +matplotlib = "*" pre-commit = "*" +pytest = "*" +"seaborn" = "*" [tool.pixi.feature.dev.tasks] -lint = "pre-commit --all-files --show-diff-on-failure" -test = "pytest -v --junitxml=pytest.xml | tee pytest-coverage.txt" +lint-all = "pre-commit run --all-files --show-diff-on-failure" +cov-test = "pytest -v --junitxml=pytest.xml | tee pytest-coverage.txt" [tool.pixi.environments] default = {features = [], solve-group = "default"} From 9cf5e015dbce749d836653543fbe57d8c5a5a7b1 Mon Sep 17 00:00:00 2001 From: Steve Chan <> Date: Fri, 8 Aug 2025 14:40:13 +0000 Subject: [PATCH 06/11] fail on pytest early --- .github/workflows/ci.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9482116d..4e687fef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,9 @@ jobs: cache-write: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - name: Check formatting and typing - run: pixi run lint-all + run: | + set -e + pixi run lint-all test-esm: @@ -50,7 +52,9 @@ jobs: cache-write: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - name: Run tests - run: pixi run cov-test + run: | + set -e + pixi run cov-test - name: Run Docker tests env: From 6d29d92681830e676a1fdd6608250ce851411b3c Mon Sep 17 00:00:00 2001 From: Steve Chan <> Date: Fri, 8 Aug 2025 14:49:11 +0000 Subject: [PATCH 07/11] disable pixi cache, pytest coverage properly --- .github/workflows/ci.yml | 8 ++----- pixi.lock | 45 +++++++++++++++++++++++++++++++++++++++- pyproject.toml | 5 +++-- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e687fef..9482116d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,9 +32,7 @@ jobs: cache-write: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - name: Check formatting and typing - run: | - set -e - pixi run lint-all + run: pixi run lint-all test-esm: @@ -52,9 +50,7 @@ jobs: cache-write: ${{ github.event_name == 'push' && github.ref_name == 'main' }} - name: Run tests - run: | - set -e - pixi run cov-test + run: pixi run cov-test - name: Run Docker tests env: diff --git a/pixi.lock b/pixi.lock index d635cac5..59428ae4 100644 --- a/pixi.lock +++ b/pixi.lock @@ -218,6 +218,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/cmarkgfm-2024.11.20-py312h66e93f0_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.3-py312hd9148b4_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.10.2-py312h8a5da7c_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.9-py312hd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cryptography-44.0.2-py312hda17c39_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda @@ -348,6 +349,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.9.0-py312h91f0f75_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-8.4.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-6.2.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.9-h9e4cc4f_1_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.9-hd8ed1ab_1.conda @@ -372,6 +374,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/statsmodels-0.14.5-py312h8b63200_0.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/toml-0.10.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.2.1-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.1-py312h66e93f0_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/twine-6.1.0-pyh29332c3_0.conda @@ -865,6 +868,21 @@ packages: - pkg:pypi/contourpy?source=compressed-mapping size: 291827 timestamp: 1754063770363 +- conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.10.2-py312h8a5da7c_0.conda + sha256: 211754cf4be7ce64b11955509fcab60cd33090633c362d4aface4a5320adbf77 + md5: f8830a2249f4b8a5f9c33cb44ad5c31a + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + - tomli + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/coverage?source=hash-mapping + size: 377963 + timestamp: 1754308562631 - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.9-py312hd8ed1ab_1.conda noarch: generic sha256: 58a637bc8328b115c9619de3fcd664ec26662083319e3c106917a1b3ee4d7594 @@ -977,7 +995,7 @@ packages: - pypi: ./ name: esm version: 3.2.1 - sha256: 12aa537c769449af8db7d3bcbe48d17b745871f014bba3d7826688770faee298 + sha256: 8bf7da0d570fb088244c8ce31ae949a0da6409e924aa756929fe01266401cd0b requires_dist: - torch>=2.2.0 - torchvision @@ -3148,6 +3166,20 @@ packages: - pkg:pypi/pytest?source=hash-mapping size: 276562 timestamp: 1750239526127 +- conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-6.2.1-pyhd8ed1ab_0.conda + sha256: 3a9fc07be76bc67aef355b78816b5117bfe686e7d8c6f28b45a1f89afe104761 + md5: ce978e1b9ed8b8d49164e90a5cdc94cd + depends: + - coverage >=7.5 + - pytest >=4.6 + - python >=3.9 + - toml + license: MIT + license_family: MIT + purls: + - pkg:pypi/pytest-cov?source=hash-mapping + size: 28216 + timestamp: 1749778064293 - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.9-h9e4cc4f_1_cpython.conda build_number: 1 sha256: 77f2073889d4c91a57bc0da73a0466d9164dbcf6191ea9c3a7be6872f784d625 @@ -3699,6 +3731,17 @@ packages: - setuptools-rust ; extra == 'docs' - tokenizers[testing] ; extra == 'dev' requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_1.conda + sha256: 34f3a83384ac3ac30aefd1309e69498d8a4aa0bf2d1f21c645f79b180e378938 + md5: b0dd904de08b7db706167240bf37b164 + depends: + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/toml?source=hash-mapping + size: 22132 + timestamp: 1734091907682 - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.2.1-pyhe01879c_2.conda sha256: 040a5a05c487647c089ad5e05ad5aff5942830db2a4e656f1e300d73436436f1 md5: 30a0a26c8abccf4b7991d590fe17c699 diff --git a/pyproject.toml b/pyproject.toml index 715e55ae..0effea71 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,11 +73,12 @@ upload-wheel = "python -m twine upload --repository pypi" matplotlib = "*" pre-commit = "*" pytest = "*" -"seaborn" = "*" +pytest-cov = "*" +seaborn = "*" [tool.pixi.feature.dev.tasks] lint-all = "pre-commit run --all-files --show-diff-on-failure" -cov-test = "pytest -v --junitxml=pytest.xml | tee pytest-coverage.txt" +cov-test = "pytest -v --junitxml=pytest.xml --cov=esm" [tool.pixi.environments] default = {features = [], solve-group = "default"} From 22f0642bd16b64daf72e11fe4d5ce073a3e7509e Mon Sep 17 00:00:00 2001 From: Ishaan Mathur Date: Fri, 15 Aug 2025 15:53:03 +0000 Subject: [PATCH 08/11] syncing oss synced oss and fixed pyright issues updating test updating test --- .gitignore | 1 + .pre-commit-config.yaml | 2 + README.md | 26 + cookbook/local/open_generate.ipynb | 1 + cookbook/local/raw_forwards.py | 4 +- cookbook/tutorials/1_esmprotein.ipynb | 4 +- cookbook/tutorials/3_gfp_design.ipynb | 1 + cookbook/tutorials/4_forge_generate.ipynb | 1 + cookbook/tutorials/5_guided_generation.ipynb | 73 +- esm/__init__.py | 1 - esm/layers/attention.py | 13 +- esm/layers/blocks.py | 9 +- esm/layers/structure_proj.py | 5 +- esm/models/esm3.py | 14 +- esm/models/function_decoder.py | 4 +- esm/models/vqvae.py | 5 +- esm/pretrained.py | 10 +- esm/sdk/api.py | 33 +- esm/sdk/base_forge_client.py | 74 +- esm/sdk/experimental/__init__.py | 14 + .../experimental/constrained_generation.py | 324 ++ .../guided_generation.py} | 2 +- esm/sdk/forge.py | 211 +- esm/sdk/retry.py | 76 + esm/sdk/sagemaker.py | 2 +- esm/tokenization/__init__.py | 5 +- esm/utils/decoding.py | 27 +- esm/utils/encoding.py | 29 +- esm/utils/forge_context_manager.py | 11 +- esm/utils/function/encode_decode.py | 13 +- esm/utils/function/lsh.py | 2 +- esm/utils/generation.py | 9 +- esm/utils/generation_test.py | 143 - esm/utils/misc.py | 53 +- esm/utils/residue_constants.py | 1158 +++++++- esm/utils/sampling.py | 15 +- esm/utils/structure/affine3d.py | 198 +- esm/utils/structure/aligner.py | 14 +- esm/utils/structure/atom_indexer.py | 15 + esm/utils/structure/metrics.py | 241 +- esm/utils/structure/mmcif_parsing.py | 469 +++ esm/utils/structure/protein_chain.py | 695 ++++- esm/utils/structure/protein_complex.py | 660 +++- esm/utils/structure/protein_structure.py | 2 +- esm/widgets/components/function_annotator.py | 4 +- esm/widgets/components/results_visualizer.py | 8 +- .../components/sasa_prompt_selector.py | 13 +- .../secondary_structure_prompt_selector.py | 13 +- .../components/sequence_prompt_selector.py | 4 +- .../components/structure_prompt_selector.py | 8 +- .../drawing/draw_function_annotations.py | 5 +- esm/widgets/utils/prompting.py | 4 +- esm/widgets/views/esm3_generation_launcher.py | 8 +- esm/widgets/views/esm3_prompt_selector.py | 4 +- esm/widgets/views/generation.py | 16 +- esm/widgets/views/inverse_folding.py | 4 +- esm/widgets/views/login.py | 5 +- esm/widgets/views/prediction.py | 4 +- pixi.lock | 2645 ++++++++++++++++- pyproject.toml | 67 +- tests/Makefile | 15 + tests/oss_pytests/Dockerfile | 19 + tests/oss_pytests/requirements.txt | 3 + tests/oss_pytests/test_oss_client.py | 85 + tests/oss_pytests/test_placeholder.py | 6 + 65 files changed, 6807 insertions(+), 802 deletions(-) create mode 100644 esm/sdk/experimental/__init__.py create mode 100644 esm/sdk/experimental/constrained_generation.py rename esm/sdk/{experimental.py => experimental/guided_generation.py} (98%) create mode 100644 esm/sdk/retry.py delete mode 100644 esm/utils/generation_test.py create mode 100644 esm/utils/structure/atom_indexer.py create mode 100644 esm/utils/structure/mmcif_parsing.py create mode 100644 tests/Makefile create mode 100644 tests/oss_pytests/Dockerfile create mode 100644 tests/oss_pytests/requirements.txt create mode 100644 tests/oss_pytests/test_oss_client.py create mode 100644 tests/oss_pytests/test_placeholder.py diff --git a/.gitignore b/.gitignore index 9e83a30d..2c904dd0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ esm.egg-info # pixi environments .pixi *.egg-info +*.pyc diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2ccba59b..269ea33b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,6 @@ # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks +exclude: (fasta|pdb|cif|mds|json)$ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v3.2.0 @@ -8,6 +9,7 @@ repos: - id: end-of-file-fixer - id: check-yaml - id: check-added-large-files + exclude: pixi.lock - id: check-merge-conflict - repo: https://github.com/seddonym/import-linter rev: v1.12.1 diff --git a/README.md b/README.md index 1d9b25c1..62cb57a9 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ - [Installation ](#installation-) +- [Available Models](#available-models-) - [ESM 3](#esm-3-) - [Quickstart for ESM3 Open](#esm3-quickstart-) - [ESM3 98B via Forge API](#esm3-forge) @@ -33,6 +34,31 @@ To get started with ESM, install the python library using pip: pip install esm ``` +## Available Models + +### ESM 3 Family + +| Model | Model Size | Release Date | Note | +|-------|------------|--------------|------| +| **Flagship Models** | | | Most users will be interested in using one of these models. | +| esm3-large-2024-03 | 98B | 2024-03 | | +| esm3-medium-2024-08 | 7B | 2024-08 | | +| esm3-small-2024-08 | 1.4B | 2024-08 | | +| **Published Models** | | | These models were used to generate all of the results in the ESM3 paper and are provided to facilitate reproducibility. | +| esm3-large-2024-03 | 98B | 2024-03 | | +| esm3-medium-2024-03 | 7B | 2024-03 | | +| esm3-small-2024-03 | 1.4B | 2024-03 | | +| **Experimental Models** | | | These models are provided for early use by researchers and are still under development. | +| esm3-medium-multimer-2024-09 | 7B | 2024-09 | | + +### ESM C Models + +| Model | Model Size | Number of Layers | Release Date | +|-------|------------|------------------|--------------| +| esmc-6b-2024-12 | 6B | 80 | 2024-12 | +| esmc-600m-2024-12 | 600M | 36 | 2024-12 | +| esmc-300m-2024-12 | 300M | 30 | 2024-12 | + ## ESM 3 [ESM3](https://www.evolutionaryscale.ai/papers/esm3-simulating-500-million-years-of-evolution-with-a-language-model) is a frontier generative model for biology, able to jointly reason across three fundamental biological properties of proteins: sequence, structure, and function. These three data modalities are represented as tracks of discrete tokens at the input and output of ESM3. You can present the model with a combination of partial inputs across the tracks, and ESM3 will provide output predictions for all the tracks. diff --git a/cookbook/local/open_generate.ipynb b/cookbook/local/open_generate.ipynb index c8cec4c1..32a72c38 100644 --- a/cookbook/local/open_generate.ipynb +++ b/cookbook/local/open_generate.ipynb @@ -38,6 +38,7 @@ "\n", "!pip install py3Dmol\n", "import py3Dmol\n", + "\n", "from esm.models.esm3 import ESM3\n", "from esm.sdk.api import ESMProtein, GenerationConfig\n", "from esm.utils.structure.protein_chain import ProteinChain" diff --git a/cookbook/local/raw_forwards.py b/cookbook/local/raw_forwards.py index c62f1734..baad28ee 100644 --- a/cookbook/local/raw_forwards.py +++ b/cookbook/local/raw_forwards.py @@ -13,9 +13,7 @@ from esm.tokenization.function_tokenizer import ( InterProQuantizedTokenizer as EsmFunctionTokenizer, ) -from esm.tokenization.sequence_tokenizer import ( - EsmSequenceTokenizer, -) +from esm.tokenization.sequence_tokenizer import EsmSequenceTokenizer from esm.utils.structure.protein_chain import ProteinChain from esm.utils.types import FunctionAnnotation diff --git a/cookbook/tutorials/1_esmprotein.ipynb b/cookbook/tutorials/1_esmprotein.ipynb index e143ff13..13017733 100644 --- a/cookbook/tutorials/1_esmprotein.ipynb +++ b/cookbook/tutorials/1_esmprotein.ipynb @@ -72,6 +72,7 @@ "outputs": [], "source": [ "from biotite.database import rcsb\n", + "\n", "from esm.sdk.api import ESMProtein\n", "from esm.utils.structure.protein_chain import ProteinChain\n", "from esm.utils.types import FunctionAnnotation\n", @@ -496,9 +497,10 @@ "# Functions for visualizing InterPro function annotations\n", "\n", "from dna_features_viewer import GraphicFeature, GraphicRecord\n", - "from esm.utils.function.interpro import InterPro, InterProEntryType\n", "from matplotlib import colormaps\n", "\n", + "from esm.utils.function.interpro import InterPro, InterProEntryType\n", + "\n", "\n", "def visualize_function_annotations(\n", " annotations: list[FunctionAnnotation],\n", diff --git a/cookbook/tutorials/3_gfp_design.ipynb b/cookbook/tutorials/3_gfp_design.ipynb index d5157e64..bde09ad5 100644 --- a/cookbook/tutorials/3_gfp_design.ipynb +++ b/cookbook/tutorials/3_gfp_design.ipynb @@ -64,6 +64,7 @@ "import matplotlib.pyplot as pl\n", "import py3Dmol\n", "import torch\n", + "\n", "from esm.sdk import client\n", "from esm.sdk.api import ESMProtein, GenerationConfig\n", "from esm.utils.structure.protein_chain import ProteinChain" diff --git a/cookbook/tutorials/4_forge_generate.ipynb b/cookbook/tutorials/4_forge_generate.ipynb index 1e61f629..7570fda9 100644 --- a/cookbook/tutorials/4_forge_generate.ipynb +++ b/cookbook/tutorials/4_forge_generate.ipynb @@ -36,6 +36,7 @@ "\n", "!pip install py3Dmol\n", "import py3Dmol\n", + "\n", "from esm.sdk import client\n", "from esm.sdk.api import ESMProtein, GenerationConfig\n", "from esm.utils.structure.protein_chain import ProteinChain" diff --git a/cookbook/tutorials/5_guided_generation.ipynb b/cookbook/tutorials/5_guided_generation.ipynb index 36fa6fbb..f04d6be3 100644 --- a/cookbook/tutorials/5_guided_generation.ipynb +++ b/cookbook/tutorials/5_guided_generation.ipynb @@ -14,13 +14,13 @@ "3. Minimize a biophysical energy function\n", "4. Use experimental screening data to guide designs with a regression model\n", "\n", - "As long as your scoring function takes a protein as input and outputs a single score, you can use it to guide designs. To accomplish this, we use an implementation of derivative-free guidance inspired by Soft Value-Based Decoding described in [Li, et al 2024](https://arxiv.org/abs/2408.08252).\n", + "As long as your scoring function takes a protein as input and outputs a single score, you can use it to guide designs. To accomplish this, we use an implementation of derivative-free guidance inspired by Soft Value-Based Decoding described in [Li, et al 2024](https://arxiv.org/abs/2408.08252) and constrained optimization using the Modified Differential Method of Multipliers from [Platt & Barr 1987](https://proceedings.neurips.cc/paper_files/paper/1987/file/a1126573153ad7e9f44ba80e99316482-Paper.pdf)\n", "\n", "In this notebook we will walk through a few examples to illustrate how to use guided generation. \n", "\n", "1. Guide towards high pTM for improved generation quality\n", "2. Generate a protein with no cysteine (C) residues\n", - "3. Maximize protein globularity by minimizing the radius of gyration\n", + "3. Maximize protein globularity by minimizing the radius of gyration, while keeping pTM high\n", "\n" ] }, @@ -49,6 +49,7 @@ "source": [ "import biotite.structure as bs\n", "import py3Dmol\n", + "\n", "from esm.sdk.api import ESMProtein, GenerationConfig\n", "from esm.sdk.experimental import ESM3GuidedDecoding, GuidedDecodingScoringFunction" ] @@ -269,6 +270,11 @@ "metadata": {}, "outputs": [], "source": [ + "# Start from a fully masked protein\n", + "PROTEIN_LENGTH = 256\n", + "starting_protein = ESMProtein(sequence=\"_\" * PROTEIN_LENGTH)\n", + "\n", + "# Call guided_generate\n", "no_cysteine_protein = no_cysteine_guided_decoding.guided_generate(\n", " protein=starting_protein,\n", " num_decoding_steps=len(starting_protein) // 8,\n", @@ -302,7 +308,20 @@ "source": [ "## Maximize Globularity\n", "\n", - "We use the radius of gyration as a proxy to maximize globularity, we also encourage generations to have high pTM" + "We use the radius of gyration as a proxy to maximize globularity, and we will also encourage generations to have high pTM by using constraints" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from esm.sdk.experimental import (\n", + " ConstraintType,\n", + " ESM3GuidedDecodingWithConstraints,\n", + " GenerationConstraint,\n", + ")" ] }, { @@ -313,12 +332,11 @@ "source": [ "class RadiousOfGyrationScoringFunction(GuidedDecodingScoringFunction):\n", " def __call__(self, protein: ESMProtein) -> float:\n", + " # Use the negative radius of gyration as the score to maximize\n", " score = -1 * self.radius_of_gyration(protein)\n", "\n", - " assert protein.ptm is not None, \"Protein must have pTM scores to be scored\"\n", - " if protein.ptm < 0.5:\n", - " # Penalize proteins with low pTM scores\n", - " score = score * 2\n", + " # Re-scale the score to be in a similar magnitude as pTM\n", + " score = score / 100.0\n", "\n", " return score\n", "\n", @@ -335,8 +353,19 @@ "metadata": {}, "outputs": [], "source": [ - "radius_guided_decoding = ESM3GuidedDecoding(\n", - " client=model, scoring_function=RadiousOfGyrationScoringFunction()\n", + "# Constrain generation to have pTM > 0.75\n", + "ptm_constraint = GenerationConstraint(\n", + " scoring_function=PTMScoringFunction(),\n", + " constraint_type=ConstraintType.GREATER_EQUAL,\n", + " value=0.75,\n", + ")\n", + "\n", + "radius_guided_decoding = ESM3GuidedDecodingWithConstraints(\n", + " client=model,\n", + " scoring_function=RadiousOfGyrationScoringFunction(),\n", + " constraints=[ptm_constraint], # Add list of constraints\n", + " damping=1.0, # Damping factor for the MMDM algorithm\n", + " learning_rate=10.0, # Learning rate for the MMDM algorithm\n", ")" ] }, @@ -346,6 +375,11 @@ "metadata": {}, "outputs": [], "source": [ + "# Start from a fully masked protein\n", + "PROTEIN_LENGTH = 256\n", + "starting_protein = ESMProtein(sequence=\"_\" * PROTEIN_LENGTH)\n", + "\n", + "# Call guided_generate\n", "radius_guided_protein = radius_guided_decoding.guided_generate(\n", " protein=starting_protein,\n", " num_decoding_steps=len(starting_protein) // 8,\n", @@ -359,11 +393,32 @@ "metadata": {}, "outputs": [], "source": [ + "# Visualize the trajectory of the constrained generation\n", + "radius_guided_decoding.visualize_latest_trajectory()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Visualize the generated protein\n", "view = py3Dmol.view(width=800, height=400)\n", "view.addModel(radius_guided_protein.to_pdb_string(), \"pdb\")\n", "view.setStyle({\"cartoon\": {\"color\": \"spectrum\"}})\n", "view.zoomTo()" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Check pTM\n", + "radius_guided_protein.ptm" + ] } ], "metadata": { diff --git a/esm/__init__.py b/esm/__init__.py index fa986f1e..1da6a555 100644 --- a/esm/__init__.py +++ b/esm/__init__.py @@ -1,2 +1 @@ __version__ = "3.2.1" - diff --git a/esm/layers/attention.py b/esm/layers/attention.py index afd88e37..564ef90c 100644 --- a/esm/layers/attention.py +++ b/esm/layers/attention.py @@ -5,15 +5,12 @@ import torch.nn.functional as F from torch import nn -from esm.layers.rotary import ( - RotaryEmbedding, - TritonRotaryEmbedding, -) +from esm.layers.rotary import RotaryEmbedding, TritonRotaryEmbedding try: - from flash_attn import flash_attn_varlen_qkvpacked_func # type:ignore -except ImportError: - flash_attn_varlen_func = None + from flash_attn import flash_attn_varlen_qkvpacked_func +except (ImportError, RuntimeError): + flash_attn_varlen_qkvpacked_func = None class MultiHeadAttention(nn.Module): @@ -117,7 +114,7 @@ def forward(self, x, seq_id): ) qkv_N3HD = self.rotary(qkv_N3HD, cu_seqlens, max_seqlen) - context_NHD = flash_attn_varlen_qkvpacked_func( + context_NHD = flash_attn_varlen_qkvpacked_func( # type: ignore qkv_N3HD, cu_seqlens, max_seqlen, softmax_scale=self.d_head**-0.5 ) context_ND = einops.rearrange(context_NHD, "n h d -> n (h d)") diff --git a/esm/layers/blocks.py b/esm/layers/blocks.py index 593b277f..76ebbe06 100644 --- a/esm/layers/blocks.py +++ b/esm/layers/blocks.py @@ -2,13 +2,8 @@ import torch.nn as nn import torch.nn.functional as F -from esm.layers.attention import ( - FlashMultiHeadAttention, - MultiHeadAttention, -) -from esm.layers.geom_attention import ( - GeometricReasoningOriginalImpl, -) +from esm.layers.attention import FlashMultiHeadAttention, MultiHeadAttention +from esm.layers.geom_attention import GeometricReasoningOriginalImpl from esm.utils.structure.affine3d import Affine3D diff --git a/esm/layers/structure_proj.py b/esm/layers/structure_proj.py index 783ddeb4..faad0fe9 100644 --- a/esm/layers/structure_proj.py +++ b/esm/layers/structure_proj.py @@ -2,10 +2,7 @@ import torch.nn as nn from esm.utils.constants.physics import BB_COORDINATES -from esm.utils.structure.affine3d import ( - Affine3D, - RotationMatrix, -) +from esm.utils.structure.affine3d import Affine3D, RotationMatrix class Dim6RotStructureHead(nn.Module): diff --git a/esm/models/esm3.py b/esm/models/esm3.py index cbe02ddd..218a8e90 100644 --- a/esm/models/esm3.py +++ b/esm/models/esm3.py @@ -13,10 +13,7 @@ from esm.layers.regression_head import RegressionHead from esm.layers.transformer_stack import TransformerStack from esm.models.function_decoder import FunctionTokenDecoder -from esm.models.vqvae import ( - StructureTokenDecoder, - StructureTokenEncoder, -) +from esm.models.vqvae import StructureTokenDecoder, StructureTokenEncoder from esm.sdk.api import ( ESM3InferenceClient, ESMProtein, @@ -32,10 +29,7 @@ from esm.tokenization import TokenizerCollectionProtocol from esm.utils import encoding from esm.utils.constants import esm3 as C -from esm.utils.constants.models import ( - ESM3_OPEN_SMALL, - normalize_model_name, -) +from esm.utils.constants.models import ESM3_OPEN_SMALL, normalize_model_name from esm.utils.decoding import decode_protein_tensor from esm.utils.generation import ( _batch_forward, @@ -50,9 +44,7 @@ get_default_sampling_config, validate_sampling_config, ) -from esm.utils.structure.affine3d import ( - build_affine3d_from_coordinates, -) +from esm.utils.structure.affine3d import build_affine3d_from_coordinates @dataclass diff --git a/esm/models/function_decoder.py b/esm/models/function_decoder.py index c4f32992..e5f1fb28 100644 --- a/esm/models/function_decoder.py +++ b/esm/models/function_decoder.py @@ -12,9 +12,7 @@ from esm.layers.regression_head import RegressionHead from esm.layers.transformer_stack import TransformerStack -from esm.tokenization.function_tokenizer import ( - InterProQuantizedTokenizer, -) +from esm.tokenization.function_tokenizer import InterProQuantizedTokenizer from esm.utils.constants import esm3 as C from esm.utils.misc import merge_annotations, merge_ranges from esm.utils.types import FunctionAnnotation diff --git a/esm/models/vqvae.py b/esm/models/vqvae.py index 0f5226a4..37bc3945 100644 --- a/esm/models/vqvae.py +++ b/esm/models/vqvae.py @@ -7,10 +7,7 @@ from esm.layers.transformer_stack import TransformerStack from esm.utils.constants import esm3 as C from esm.utils.misc import knn_graph -from esm.utils.structure.affine3d import ( - Affine3D, - build_affine3d_from_coordinates, -) +from esm.utils.structure.affine3d import Affine3D, build_affine3d_from_coordinates from esm.utils.structure.predicted_aligned_error import ( compute_predicted_aligned_error, compute_tm, diff --git a/esm/pretrained.py b/esm/pretrained.py index b9121511..e452e1d2 100644 --- a/esm/pretrained.py +++ b/esm/pretrained.py @@ -6,14 +6,8 @@ from esm.models.esm3 import ESM3 from esm.models.esmc import ESMC from esm.models.function_decoder import FunctionTokenDecoder -from esm.models.vqvae import ( - StructureTokenDecoder, - StructureTokenEncoder, -) -from esm.tokenization import ( - get_esm3_model_tokenizers, - get_esmc_model_tokenizers, -) +from esm.models.vqvae import StructureTokenDecoder, StructureTokenEncoder +from esm.tokenization import get_esm3_model_tokenizers, get_esmc_model_tokenizers from esm.utils.constants.esm3 import data_root from esm.utils.constants.models import ( ESM3_FUNCTION_DECODER_V0, diff --git a/esm/sdk/api.py b/esm/sdk/api.py index 7d092fd7..0212ddcd 100644 --- a/esm/sdk/api.py +++ b/esm/sdk/api.py @@ -2,27 +2,19 @@ from abc import ABC from copy import deepcopy -from typing import List, Sequence +from typing import Sequence import attr import torch from attr import asdict, define import esm.utils.constants.api as C -from esm.tokenization import ( - TokenizerCollectionProtocol, - get_esm3_model_tokenizers, -) +from esm.tokenization import TokenizerCollectionProtocol, get_esm3_model_tokenizers from esm.utils import encoding from esm.utils.constants.models import ESM3_OPEN_SMALL -from esm.utils.misc import ( - get_chainbreak_boundaries_from_sequence, -) +from esm.utils.misc import get_chainbreak_boundaries_from_sequence from esm.utils.structure.protein_chain import ProteinChain -from esm.utils.structure.protein_complex import ( - SINGLE_LETTER_CHAIN_IDS, - ProteinComplex, -) +from esm.utils.structure.protein_complex import SINGLE_LETTER_CHAIN_IDS, ProteinComplex from esm.utils.types import FunctionAnnotation, PathOrBuffer @@ -43,7 +35,6 @@ class ESMProtein(ProteinType): plddt: torch.Tensor | None = None ptm: torch.Tensor | None = None - # When calling EvolutionaryScale API, use this flag to disclose any # sequences that may potentially have concerns. # Such sequences may not go through standard safety filter for approved users. @@ -79,12 +70,9 @@ def from_pdb( def from_protein_chain( cls, protein_chain: ProteinChain, with_annotations: bool = False ) -> ESMProtein: - # By default, we don't annotate with DSSP / SASA, which are expensive. - # If mkdssp is installed, we can annotate with a flag. if with_annotations: return ESMProtein( sequence=protein_chain.sequence, - secondary_structure=protein_chain.dssp().tolist(), sasa=protein_chain.sasa().tolist(), function_annotations=None, coordinates=torch.tensor(protein_chain.atom37_positions), @@ -123,7 +111,8 @@ def to_pdb(self, pdb_path: PathOrBuffer) -> None: protein_complex.to_pdb(pdb_path) def to_pdb_string(self) -> str: - protein_chain = self.to_protein_chain() + # Note: This was modified to match .to_pdb() behavior. We can revisit this at some point + protein_chain = self.to_protein_complex().infer_oxygen() return protein_chain.to_pdb_string() def to_protein_chain(self) -> ProteinChain: @@ -172,6 +161,7 @@ def to_protein_complex( if gt_chains is not None else SINGLE_LETTER_CHAIN_IDS[i], entity_id=gt_chains[i].entity_id if gt_chains is not None else None, + confidence=self.plddt[start:end] if self.plddt is not None else None, ) pred_chains.append(pred_chain) return ProteinComplex.from_chains(pred_chains) @@ -321,8 +311,6 @@ class InverseFoldingConfig: temperature: float = 1.0 - - ## Low Level Endpoint Types @define class SamplingTrackConfig: @@ -382,22 +370,23 @@ class LogitsConfig: # Embeddings. return_embeddings: bool = False return_hidden_states: bool = False + return_mean_embedding: bool = False + return_mean_hidden_states: bool = False ith_hidden_layer: int = -1 - - - @define class LogitsOutput: logits: ForwardTrackData | None = None embeddings: torch.Tensor | None = None + mean_embedding: torch.Tensor | None = None # Residue annotations is multi-hot, so deserves special treatment # It's not a categorical distribution, but instead a bernoulli, so # softmax across the last dimension is _wrong_ residue_annotation_logits: torch.Tensor | None = None hidden_states: torch.Tensor | None = None + mean_hidden_state: torch.Tensor | None = None @define diff --git a/esm/sdk/base_forge_client.py b/esm/sdk/base_forge_client.py index aa679bca..ff05b541 100644 --- a/esm/sdk/base_forge_client.py +++ b/esm/sdk/base_forge_client.py @@ -70,11 +70,13 @@ def __exit__(self, exc_type, exc_val, exc_tb): def prepare_request( self, request: dict[str, Any], - potential_sequence_of_concern: bool = False, + potential_sequence_of_concern: bool | None = None, return_bytes: bool = False, headers: dict[str, str] = {}, ) -> tuple[dict[str, Any], dict[str, str]]: - request["potential_sequence_of_concern"] = potential_sequence_of_concern + if potential_sequence_of_concern is not None: + request["potential_sequence_of_concern"] = potential_sequence_of_concern + headers = {**self.headers, **headers} if return_bytes: headers["return-bytes"] = "true" @@ -103,42 +105,58 @@ async def _async_post( self, endpoint, request, - potential_sequence_of_concern: bool = False, + potential_sequence_of_concern: bool | None = None, params: dict[str, Any] = {}, headers: dict[str, str] = {}, return_bytes: bool = False, ): - request, headers = self.prepare_request( - request, potential_sequence_of_concern, return_bytes, headers - ) - response = await self.async_client.post( - url=urljoin(self.url, f"/api/v1/{endpoint}"), - json=request, - params=params, - headers=headers, - timeout=self.request_timeout, - ) - data = self.prepare_data(response, endpoint) - return data + try: + request, headers = self.prepare_request( + request, potential_sequence_of_concern, return_bytes, headers + ) + response = await self.async_client.post( + url=urljoin(self.url, f"/api/v1/{endpoint}"), + json=request, + params=params, + headers=headers, + timeout=self.request_timeout, + ) + data = self.prepare_data(response, endpoint) + return data + except ESMProteinError as e: + raise e + except Exception as e: + raise ESMProteinError( + error_code=500, + error_msg=f"Failed to submit request to {endpoint}. Error: {e}", + ) def _post( self, endpoint, request, - potential_sequence_of_concern: bool = False, + potential_sequence_of_concern: bool | None = None, params: dict[str, Any] = {}, headers: dict[str, str] = {}, return_bytes: bool = False, ): - request, headers = self.prepare_request( - request, potential_sequence_of_concern, return_bytes, headers - ) - response = self.client.post( - url=urljoin(self.url, f"/api/v1/{endpoint}"), - json=request, - params=params, - headers=headers, - timeout=self.request_timeout, - ) - data = self.prepare_data(response, endpoint) - return data + try: + request, headers = self.prepare_request( + request, potential_sequence_of_concern, return_bytes, headers + ) + response = self.client.post( + url=urljoin(self.url, f"/api/v1/{endpoint}"), + json=request, + params=params, + headers=headers, + timeout=self.request_timeout, + ) + data = self.prepare_data(response, endpoint) + return data + except ESMProteinError as e: + raise e + except Exception as e: + raise ESMProteinError( + error_code=500, + error_msg=f"Failed to submit request to {endpoint}. Error: {e}", + ) diff --git a/esm/sdk/experimental/__init__.py b/esm/sdk/experimental/__init__.py new file mode 100644 index 00000000..d583d825 --- /dev/null +++ b/esm/sdk/experimental/__init__.py @@ -0,0 +1,14 @@ +from .constrained_generation import ( + ConstraintType, + ESM3GuidedDecodingWithConstraints, + GenerationConstraint, +) +from .guided_generation import ESM3GuidedDecoding, GuidedDecodingScoringFunction + +__all__ = [ + "ConstraintType", + "ESM3GuidedDecodingWithConstraints", + "GenerationConstraint", + "ESM3GuidedDecoding", + "GuidedDecodingScoringFunction", +] diff --git a/esm/sdk/experimental/constrained_generation.py b/esm/sdk/experimental/constrained_generation.py new file mode 100644 index 00000000..967b7519 --- /dev/null +++ b/esm/sdk/experimental/constrained_generation.py @@ -0,0 +1,324 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from enum import Enum +from typing import List + +import matplotlib.pyplot as plt +import numpy as np +import torch +from matplotlib.collections import LineCollection +from matplotlib.colors import Normalize +from tqdm import tqdm + +from esm.sdk import batch_executor +from esm.sdk.api import ( + ESM3InferenceClient, + ESMProtein, + ESMProteinError, + ESMProteinTensor, + SamplingConfig, + SamplingTrackConfig, +) +from esm.sdk.experimental.guided_generation import ( + ESM3GuidedDecoding, + GuidedDecodingScoringFunction, +) + + +class ConstraintType(Enum): + GREATER_EQUAL = "greater_equal" # f(x) ≥ threshold + LESS_EQUAL = "less_equal" # f(x) ≤ threshold + EQUAL = "equal" # f(x) = threshold + + +@dataclass(slots=True) +class GenerationConstraint: + """ + A single inequality or equality constraint. + + Parameters + ---------- + scoring_function + Maps a protein ➜ real value (e.g. pTM, length, …). + value + Target value for inequality or equality constraint. + constraint_type + Type of constraint to apply. + - GREATER_EQUAL: f(x) ≥ value + - LESS_EQUAL: f(x) ≤ value + - EQUAL: f(x) = value (equality) + """ + + scoring_function: GuidedDecodingScoringFunction + value: float + constraint_type: ConstraintType = ConstraintType.GREATER_EQUAL + lambda_: float = field(default=0.0, init=False) # dual variable (MDMM) + + def g(self, x: float) -> float: + """ + Canonical form: + + • inequalities → g(x) ≤ 0 + • equalities → h(x) (we still return a scalar, no ≤) + """ + if self.constraint_type is ConstraintType.GREATER_EQUAL: + return self.value - x + if self.constraint_type is ConstraintType.LESS_EQUAL: + return x - self.value + # equality: h(x) = x - value (we will *not* project λ) + return x - self.value + + def update_lambda(self, g: float, eta: float, gamma: float) -> None: + """ + Update the dual variable λ according to the MDMM update rule. + """ + if self.constraint_type is ConstraintType.EQUAL: + self.lambda_ += eta * g # no projection for equality constraints + else: + self.lambda_ = max(0.0, self.lambda_ + eta * g) + + def copy(self) -> GenerationConstraint: + """ + Create a copy of this constraint. + """ + c = GenerationConstraint( + scoring_function=self.scoring_function, + value=self.value, + constraint_type=self.constraint_type, + ) + c.lambda_ = self.lambda_ # copy the dual variable + return c + + +class ESM3GuidedDecodingWithConstraints(ESM3GuidedDecoding): + """ + Derivative-free guided decoding with constraints. + + Uses the Modified Differential Method of Multipliers (MDMM) to + guarantee convergence to the constrained optimum without + hand-tuning penalty weights. + + References: + [1] Platt, John, and Alan Barr. "Constrained differential optimization." Neural Information Processing Systems. 1987. + [2] https://www.engraved.blog/how-we-can-make-machine-learning-algorithms-tunable/ + """ + + def __init__( + self, + client: ESM3InferenceClient, + scoring_function: GuidedDecodingScoringFunction, + constraints: GenerationConstraint | list[GenerationConstraint], + *, + damping: float = 10.0, + learning_rate: float = 1.0, + ): + super().__init__(client, scoring_function) + + if isinstance(constraints, GenerationConstraint): + constraints = [constraints] + + self.constraints = [c.copy() for c in constraints] + self.gamma = float(damping) + self.eta = float(learning_rate) + + self.recorder: TrajectoryRecorder | None = None + + def guided_generate( + self, + protein: ESMProtein, + num_decoding_steps: int, + num_samples_per_step: int, + denoised_prediction_temperature: float = 0.0, + track: str = "sequence", + verbose: bool = True, + ) -> ESMProtein: + # Reset the trajectory recorder + self.recorder = TrajectoryRecorder() + + protein_tensor = self.client.encode(protein) + assert not isinstance(protein_tensor, ESMProteinError) + + if track == "structure": + protein_tensor = self.maybe_add_default_structure_tokens(protein_tensor) + + n_masked = self.get_number_of_masked_positions(protein_tensor, track=track) + n_unmask = n_masked // num_decoding_steps + + best_reward = float("-inf") + + if verbose: + pbar = tqdm(range(num_decoding_steps), desc="S=-inf λ=0.00") + else: + pbar = range(num_decoding_steps) + + for step in pbar: + # Last iteration: unmask whatever is left + if step == num_decoding_steps - 1: + n_unmask = self.get_number_of_masked_positions( + protein_tensor, track=track + ) + + # ---------- propose & evaluate M samples (parallel-safe) ---- # + def _propose_and_eval(pt: ESMProteinTensor): + new_pt = self.randomly_unmask_positions(pt, n_unmask, track=track) + reward, g_val, raw_vals = self._score_and_constraints( + new_pt, denoised_prediction_temperature + ) + return new_pt, reward, g_val, raw_vals + + if self._use_batch_executor: + with batch_executor(show_progress=False) as ex: + results = ex.execute_batch( + user_func=_propose_and_eval, + pt=[protein_tensor] * num_samples_per_step, + ) + + if isinstance(results, Exception): + raise results + samples, rewards, gh_lists, val_lists = zip(*results) # type: ignore + else: + samples, rewards, gh_lists, val_lists = [], [], [], [] + for _ in range(num_samples_per_step): + s, r, g, c = _propose_and_eval(protein_tensor) + samples.append(s) + rewards.append(r) + gh_lists.append(g) + val_lists.append(c) + + # -------- compute MDMM lagrangian for each sample ----------- + lags = [self._lagrangian(r, ghs) for r, ghs in zip(rewards, gh_lists)] + + best_idx = int(torch.tensor(lags).argmin()) + protein_tensor = samples[best_idx] + best_reward = rewards[best_idx] + best_g_vals = gh_lists[best_idx] + + # -------- dual updates (MDMM) ----------------- + for g, c in zip(best_g_vals, self.constraints): + c.update_lambda(g, self.eta, self.gamma) + + self.recorder.log( + step=step, + reward=best_reward, + g_list=best_g_vals, + lambda_list=[c.lambda_ for c in self.constraints], + ) + + if verbose and isinstance(pbar, tqdm): + lam_str = ", ".join( + f"λ_{i}={c.lambda_:.2f}" for i, c in enumerate(self.constraints) + ) + pbar.set_description(f"S={best_reward:+.3f} {lam_str}") + + final = self.client.forward_and_sample( + protein_tensor, + sampling_configuration=SamplingConfig( + sequence=SamplingTrackConfig(temperature=0.0), + structure=SamplingTrackConfig(temperature=0.0), + ), + ) + assert not isinstance(final, ESMProteinError) + decoded = self.client.decode(final.protein_tensor) + assert not isinstance(decoded, ESMProteinError) + return decoded + + def visualize_latest_trajectory( + self, constraint_idx: int = 0, cmap: str = "viridis" + ) -> None: + """ + Visualise the trajectory of the latest optimisation run. + If you optimise multiple constraints, pick which one to plot via `constraint_idx`. + """ + if not self.recorder: + raise ValueError("No trajectory recorder available.") + + steps, g_vals, rewards = self.recorder.as_arrays(constraint_idx) + self.recorder.plot_line(constraint_idx=constraint_idx, cmap=cmap) + + def _score_and_constraints( + self, pt: ESMProteinTensor, temp: float + ) -> tuple[float, list[float], list[float]]: + protein = self.predict_denoised(pt, temperature=temp) + reward = self.scoring_function(protein) + vals, ghs = [], [] + for c in self.constraints: + val = c.scoring_function(protein) + vals.append(val) + ghs.append(c.g(val)) + return reward, ghs, vals + + def _lagrangian(self, reward: float, g_vals: list[float]) -> float: + """ + MDMM L(x, λ) = -reward + Σ_i (λ_i - γ g_i) * g_i + (reward is to be maximised ⇒ we minimise -reward) + """ + lag = -reward + for g, c in zip(g_vals, self.constraints): + lag += (c.lambda_ - self.gamma * g) * g + return lag + + +@dataclass +class TrajectoryRecorder: + steps: List[int] = field(default_factory=list) + rewards: List[float] = field(default_factory=list) + g_vals: List[List[float]] = field( + default_factory=list + ) # each step → list of constraints + lambdas: List[List[float]] = field(default_factory=list) # each step → list of λ s + + def log( + self, step: int, reward: float, g_list: list[float], lambda_list: list[float] + ) -> None: + """Append one optimisation step to the trajectory.""" + self.steps.append(step) + self.rewards.append(reward) + self.g_vals.append(list(g_list)) + self.lambdas.append(list(lambda_list)) + + def as_arrays(self, constraint_idx: int = 0): + """ + Return numpy arrays suitable for plotting. + If you optimise multiple constraints, pick which one to plot via `constraint_idx`. + """ + return ( + np.asarray(self.steps), + np.asarray([g[constraint_idx] for g in self.g_vals]), + np.asarray(self.rewards), + ) + + def plot_line(self, constraint_idx: int = 0, cmap: str = "viridis"): + """ + Continuous line with markers and a colour-gradient that follows the optimisation step. + """ + steps, x_vals, y_vals = self.as_arrays(constraint_idx) + + # build coloured line segments + points = np.column_stack([x_vals, y_vals]) + segments = np.concatenate([points[:-1, None, :], points[1:, None, :]], axis=1) + + norm = Normalize(vmin=steps.min(), vmax=steps.max()) + lc = LineCollection(segments, cmap=cmap, norm=norm, linewidth=2) # type: ignore + lc.set_array(steps) + + fig, ax = plt.subplots() + ax.add_collection(lc) + ax.scatter( + x_vals, + y_vals, + c=steps, + cmap=cmap, + norm=norm, + marker="o", + edgecolor="k", + zorder=3, + ) + + ax.axvline(0, linestyle="--", color="grey") + ax.set_xlabel("constraint value g(x) (≤ 0 is feasible)") + ax.set_ylabel("reward R(x)") + ax.set_title("Trajectory in constraint–reward space") + plt.colorbar(lc, label="optimisation step") + plt.tight_layout() + plt.show() diff --git a/esm/sdk/experimental.py b/esm/sdk/experimental/guided_generation.py similarity index 98% rename from esm/sdk/experimental.py rename to esm/sdk/experimental/guided_generation.py index 39ad6703..9acd32e8 100644 --- a/esm/sdk/experimental.py +++ b/esm/sdk/experimental/guided_generation.py @@ -44,7 +44,7 @@ def __init__( self._use_batch_executor = True else: raise ValueError( - "client must be an instance of ESM3 or ESM3ForgeInferenceClient" + f"client must be an instance of ESM3 or ESM3ForgeInferenceClient. Got {type(client)}" ) self.client = client diff --git a/esm/sdk/forge.py b/esm/sdk/forge.py index d9244993..e9bb2e3d 100644 --- a/esm/sdk/forge.py +++ b/esm/sdk/forge.py @@ -1,15 +1,10 @@ import asyncio import base64 -import inspect import pickle from concurrent.futures import ThreadPoolExecutor -from contextvars import ContextVar -from functools import wraps -from typing import Any, Literal, Sequence, cast +from typing import Any, Sequence import torch -from attr import asdict -from tenacity import retry, retry_if_result, stop_after_attempt, wait_exponential from esm.sdk.api import ( MSA, @@ -29,17 +24,11 @@ SamplingTrackConfig, ) from esm.sdk.base_forge_client import _BaseForgeInferenceClient +from esm.sdk.retry import retry_decorator from esm.utils.constants.api import MIMETYPE_ES_PICKLE -from esm.utils.misc import ( - deserialize_tensors, - maybe_list, - maybe_tensor, -) -from esm.utils.sampling import validate_sampling_config +from esm.utils.misc import deserialize_tensors, maybe_list, maybe_tensor from esm.utils.types import FunctionAnnotation -skip_retries_var = ContextVar("skip_retries", default=False) - def _list_to_function_annotations(l) -> list[FunctionAnnotation] | None: if l is None or len(l) <= 0: @@ -47,21 +36,17 @@ def _list_to_function_annotations(l) -> list[FunctionAnnotation] | None: return [FunctionAnnotation(*t) for t in l] -def retry_if_specific_error(exception): - """ - We only retry on specific errors. - Currently we retry for 502 (bad gateway) and 429 (rate limit) - """ - return isinstance(exception, ESMProteinError) and exception.error_code in { - 429, - 502, - 504, - } +def _maybe_logits(data: dict[str, Any], track: str, return_bytes: bool = False): + ret = data.get("logits", {}).get(track, None) + # TODO(s22chan): just return this when removing return_bytes + return ret if ret is None or not return_bytes else maybe_tensor(ret) -def log_retry_attempt(retry_state): - print( - f"Retrying... Attempt {retry_state.attempt_number} after {retry_state.next_action.sleep}s due to: {retry_state.outcome.result()}" +def _maybe_b64_decode(obj, return_bytes: bool): + return ( + deserialize_tensors(base64.b64decode(obj)) + if return_bytes and isinstance(obj, str) + else obj ) @@ -77,45 +62,6 @@ def _validate_protein_tensor_input(input): ) -def retry_decorator(func): - """ - A static method that returns a retry decorator. This decorator uses the - instance's retry settings. - """ - - @wraps(func) - async def async_wrapper(instance, *args, **kwargs): - if skip_retries_var.get(): - return await func(instance, *args, **kwargs) - retry_decorator = retry( - retry=retry_if_result(retry_if_specific_error), - wait=wait_exponential( - multiplier=1, min=instance.min_retry_wait, max=instance.max_retry_wait - ), - stop=stop_after_attempt(instance.max_retry_attempts), - before_sleep=log_retry_attempt, - ) - # Apply the retry decorator to the function - return await retry_decorator(func)(instance, *args, **kwargs) - - @wraps(func) - def wrapper(instance, *args, **kwargs): - if skip_retries_var.get(): - return func(instance, *args, **kwargs) - retry_decorator = retry( - retry=retry_if_result(retry_if_specific_error), - wait=wait_exponential( - multiplier=1, min=instance.min_retry_wait, max=instance.max_retry_wait - ), - stop=stop_after_attempt(instance.max_retry_attempts), - before_sleep=log_retry_attempt, - ) - # Apply the retry decorator to the function - return retry_decorator(func)(instance, *args, **kwargs) - - return async_wrapper if inspect.iscoroutinefunction(func) else wrapper - - class SequenceStructureForgeInferenceClient(_BaseForgeInferenceClient): def __init__( self, @@ -147,13 +93,9 @@ def __init__( ) @staticmethod - def _process_fold_request( - sequence: str, - model_name: str | None, - ): + def _process_fold_request(sequence: str, model_name: str | None): request: dict[str, Any] = {"sequence": sequence} - request["model"] = model_name return request @@ -164,12 +106,15 @@ def _process_fold_response(data: dict[str, Any], sequence: str) -> ESMProtein: sequence=sequence, coordinates=maybe_tensor(data["coordinates"], convert_none_to_nan=True), ptm=maybe_tensor(data.get("ptm", None)), - plddt=maybe_tensor(data.get("plddt", None)), + plddt=maybe_tensor(data.get("plddt", None), convert_none_to_nan=True), ) @staticmethod def process_inverse_fold_request( - coordinates: torch.Tensor, config: InverseFoldingConfig, model_name: str | None + coordinates: torch.Tensor, + sequence: str | None, + config: InverseFoldingConfig, + model_name: str | None, ): inverse_folding_config = { "invalid_ids": config.invalid_ids, @@ -178,6 +123,7 @@ def process_inverse_fold_request( request = { "coordinates": maybe_list(coordinates, convert_nan_to_none=True), "inverse_folding_config": inverse_folding_config, + "sequence": sequence, } if model_name is not None: request["model"] = model_name @@ -222,13 +168,13 @@ async def async_fold( del potential_sequence_of_concern request = self._process_fold_request( - sequence, - model_name if model_name is not None else self.model, + sequence, model_name if model_name is not None else self.model ) - # Intentionally not catching errors, so our higher level logic such as automatic - # batch runner gets a chance to handle different errors properly. - data = await self._async_post("fold", request) + try: + data = await self._async_post("fold", request) + except ESMProteinError as e: + return e return self._process_fold_response(data, sequence) @@ -249,16 +195,17 @@ def fold( potential_sequence_of_concern: this parameter is largely deprecated and ignored by the folding endpoint. """ + del potential_sequence_of_concern request = self._process_fold_request( - sequence, - model_name if model_name is not None else self.model, + sequence, model_name if model_name is not None else self.model ) - # Intentionally not catching errors, so our higher level logic such as automatic - # batch runner gets a chance to handle different errors properly. - data = self._post("fold", request) + try: + data = self._post("fold", request) + except ESMProteinError as e: + return e return self._process_fold_response(data, sequence) @@ -268,6 +215,7 @@ async def async_inverse_fold( coordinates: torch.Tensor, config: InverseFoldingConfig, potential_sequence_of_concern: bool, + sequence: str | None = None, model_name: str | None = None, ) -> ESMProtein | ESMProteinError: """Generate protein sequence from its structure. @@ -282,14 +230,18 @@ async def async_inverse_fold( model_name: Override the client level model name if needed. """ request = self.process_inverse_fold_request( - coordinates, config, model_name if model_name is not None else self.model + coordinates, + sequence, + config, + model_name if model_name is not None else self.model, ) - # Intentionally not catching errors, so our higher level logic such as automatic - # batch runner gets a chance to handle different errors properly. - data = await self._async_post( - "inverse_fold", request, potential_sequence_of_concern - ) + try: + data = await self._async_post( + "inverse_fold", request, potential_sequence_of_concern + ) + except ESMProteinError as e: + return e return ESMProtein(sequence=data["sequence"]) @@ -299,6 +251,7 @@ def inverse_fold( coordinates: torch.Tensor, config: InverseFoldingConfig, potential_sequence_of_concern: bool, + sequence: str | None = None, model_name: str | None = None, ) -> ESMProtein | ESMProteinError: """Generate protein sequence from its structure. @@ -313,12 +266,16 @@ def inverse_fold( model_name: Override the client level model name if needed. """ request = self.process_inverse_fold_request( - coordinates, config, model_name if model_name is not None else self.model + coordinates, + sequence, + config, + model_name if model_name is not None else self.model, ) - # Intentionally not catching errors, so our higher level logic such as automatic - # batch runner gets a chance to handle different errors properly. - data = self._post("inverse_fold", request, potential_sequence_of_concern) + try: + data = self._post("inverse_fold", request, potential_sequence_of_concern) + except ESMProteinError as e: + return e return ESMProtein(sequence=data["sequence"]) @@ -442,6 +399,8 @@ def _field_to_tensor(field, convert_none_to_nan: bool = False): def _process_forward_and_sample_request( input: ESMProteinTensor, sampling_configuration: SamplingConfig, model_name: str ) -> dict[str, Any]: + from esm.utils.sampling import validate_sampling_config + _validate_protein_tensor_input(input) validate_sampling_config(sampling_configuration, on_invalid="raise") @@ -623,7 +582,9 @@ def _process_logits_request( "function": config.function, "residue_annotations": config.residue_annotations, "return_embeddings": config.return_embeddings, + "return_mean_embedding": config.return_mean_embedding, "return_hidden_states": config.return_hidden_states, + "return_mean_hidden_states": config.return_mean_hidden_states, "ith_hidden_layer": config.ith_hidden_layer, } @@ -634,34 +595,28 @@ def _process_logits_request( def _process_logits_response( data: dict[str, Any], return_bytes: bool ) -> LogitsOutput: - def _maybe_logits(track: str): - ret = data.get("logits", {}).get(track, None) - # TODO(s22chan): just return this when removing return_bytes - return ret if ret is None or not return_bytes else maybe_tensor(ret) - - def _maybe_b64_decode(obj): - return ( - deserialize_tensors(base64.b64decode(obj)) - if return_bytes and isinstance(obj, str) - else obj - ) - - logits = _maybe_b64_decode(data["logits"]) + logits = _maybe_b64_decode(data["logits"], return_bytes) data["logits"] = dict(logits) if logits is not None else logits - data["embeddings"] = _maybe_b64_decode(data["embeddings"]) - data["hidden_states"] = _maybe_b64_decode(data["hidden_states"]) + data["embeddings"] = _maybe_b64_decode(data["embeddings"], return_bytes) + data["hidden_states"] = _maybe_b64_decode(data["hidden_states"], return_bytes) return LogitsOutput( logits=ForwardTrackData( - sequence=_maybe_logits("sequence"), - structure=_maybe_logits("structure"), - secondary_structure=_maybe_logits("secondary_structure"), - sasa=_maybe_logits("sasa"), - function=_maybe_logits("function"), + sequence=_maybe_logits(data, "sequence", return_bytes), + structure=_maybe_logits(data, "structure", return_bytes), + secondary_structure=_maybe_logits( + data, "secondary_structure", return_bytes + ), + sasa=_maybe_logits(data, "sasa", return_bytes), + function=_maybe_logits(data, "function", return_bytes), ), embeddings=maybe_tensor(data["embeddings"]), - residue_annotation_logits=_maybe_logits("residue_annotation"), + mean_embedding=data["mean_embedding"], + residue_annotation_logits=_maybe_logits( + data, "residue_annotation", return_bytes + ), hidden_states=maybe_tensor(data["hidden_states"]), + mean_hidden_state=maybe_tensor(data["mean_hidden_state"]), ) @retry_decorator @@ -741,8 +696,8 @@ async def safe_generate(protein, config): try: res = self.async_generate(protein, config) return await res - except Exception as e: - return ESMProteinError(500, str(e)) + except ESMProteinError as e: + return e tasks = [ safe_generate(protein, config) for protein, config in zip(inputs, configs) @@ -1009,6 +964,7 @@ def _process_logits_request( logits_config = { "sequence": config.sequence, "return_embeddings": config.return_embeddings, + "return_mean_embedding": config.return_mean_embedding, "return_hidden_states": config.return_hidden_states, "ith_hidden_layer": config.ith_hidden_layer, } @@ -1019,26 +975,17 @@ def _process_logits_request( def _process_logits_response( data: dict[str, Any], return_bytes: bool ) -> LogitsOutput: - def _maybe_logits(track: str): - ret = data.get("logits", {}).get(track, None) - # TODO(s22chan): just return this when removing return_bytes - return ret if ret is None or not return_bytes else maybe_tensor(ret) - - def _maybe_b64_decode(obj): - return ( - deserialize_tensors(base64.b64decode(obj)) - if return_bytes and isinstance(obj, str) - else obj - ) - - logits = _maybe_b64_decode(data["logits"]) + logits = _maybe_b64_decode(data["logits"], return_bytes) data["logits"] = dict(logits) if logits is not None else logits - data["embeddings"] = _maybe_b64_decode(data["embeddings"]) - data["hidden_states"] = _maybe_b64_decode(data["hidden_states"]) + data["embeddings"] = _maybe_b64_decode(data["embeddings"], return_bytes) + data["hidden_states"] = _maybe_b64_decode(data["hidden_states"], return_bytes) output = LogitsOutput( - logits=ForwardTrackData(sequence=_maybe_logits("sequence")), + logits=ForwardTrackData( + sequence=_maybe_logits(data, "sequence", return_bytes) + ), embeddings=maybe_tensor(data["embeddings"]), + mean_embedding=data["mean_embedding"], hidden_states=maybe_tensor(data["hidden_states"]), ) return output diff --git a/esm/sdk/retry.py b/esm/sdk/retry.py new file mode 100644 index 00000000..16c354b6 --- /dev/null +++ b/esm/sdk/retry.py @@ -0,0 +1,76 @@ +import inspect +from contextvars import ContextVar +from functools import wraps + +import httpx +from tenacity import ( + retry, + retry_if_exception_type, + retry_if_result, + stop_after_attempt, + wait_incrementing, +) + +from esm.sdk.api import ESMProteinError + +skip_retries_var = ContextVar("skip_retries", default=False) + + +def retry_if_specific_error(exception): + """ + We only retry on specific errors. + """ + return isinstance(exception, ESMProteinError) and exception.error_code in { + 429, + 500, + 502, + 504, + 500, + } + + +def log_retry_attempt(retry_state): + print( + f"Retrying... Attempt {retry_state.attempt_number} after {retry_state.next_action.sleep}s due to: {retry_state.outcome.result()}" + ) + + +def retry_decorator(func): + """ + A static method that returns a retry decorator. This decorator uses the + instance's retry settings. + """ + + @wraps(func) + async def async_wrapper(instance, *args, **kwargs): + if skip_retries_var.get(): + return await func(instance, *args, **kwargs) + retry_decorator = retry( + retry=retry_if_result(retry_if_specific_error) + | retry_if_exception_type(httpx.ConnectTimeout), # ADDED + wait=wait_incrementing( + increment=1, start=instance.min_retry_wait, max=instance.max_retry_wait + ), + stop=stop_after_attempt(instance.max_retry_attempts), + before_sleep=log_retry_attempt, + ) + # Apply the retry decorator to the function + return await retry_decorator(func)(instance, *args, **kwargs) + + @wraps(func) + def wrapper(instance, *args, **kwargs): + if skip_retries_var.get(): + return func(instance, *args, **kwargs) + retry_decorator = retry( + retry=retry_if_result(retry_if_specific_error) + | retry_if_exception_type(httpx.ConnectTimeout), # ADDED + wait=wait_incrementing( + increment=1, start=instance.min_retry_wait, max=instance.max_retry_wait + ), + stop=stop_after_attempt(instance.max_retry_attempts), + before_sleep=log_retry_attempt, + ) + # Apply the retry decorator to the function + return retry_decorator(func)(instance, *args, **kwargs) + + return async_wrapper if inspect.iscoroutinefunction(func) else wrapper diff --git a/esm/sdk/sagemaker.py b/esm/sdk/sagemaker.py index 219a4442..79232054 100644 --- a/esm/sdk/sagemaker.py +++ b/esm/sdk/sagemaker.py @@ -22,7 +22,7 @@ def __init__(self, endpoint_name: str, model: str | None = None): self._boto3_client = boto3.client(service_name="sagemaker-runtime") - def _post(self, endpoint, request, potential_sequence_of_concern): + def _post(self, endpoint, request, potential_sequence_of_concern: bool = False): request["potential_sequence_of_concern"] = potential_sequence_of_concern request["model"] = request.get("model", None) invocations_request = { diff --git a/esm/tokenization/__init__.py b/esm/tokenization/__init__.py index ea609225..6db76554 100644 --- a/esm/tokenization/__init__.py +++ b/esm/tokenization/__init__.py @@ -1,10 +1,7 @@ from dataclasses import dataclass from typing import Protocol -from esm.utils.constants.models import ( - ESM3_OPEN_SMALL, - normalize_model_name, -) +from esm.utils.constants.models import ESM3_OPEN_SMALL, normalize_model_name from .function_tokenizer import InterProQuantizedTokenizer from .residue_tokenizer import ResidueAnnotationsTokenizer diff --git a/esm/utils/decoding.py b/esm/utils/decoding.py index 18dff27d..1fe256b6 100644 --- a/esm/utils/decoding.py +++ b/esm/utils/decoding.py @@ -10,24 +10,12 @@ from esm.models.vqvae import StructureTokenDecoder from esm.sdk.api import ESMProtein, ESMProteinTensor from esm.tokenization import TokenizerCollectionProtocol -from esm.tokenization.function_tokenizer import ( - InterProQuantizedTokenizer, -) -from esm.tokenization.residue_tokenizer import ( - ResidueAnnotationsTokenizer, -) -from esm.tokenization.sasa_tokenizer import ( - SASADiscretizingTokenizer, -) -from esm.tokenization.sequence_tokenizer import ( - EsmSequenceTokenizer, -) -from esm.tokenization.ss_tokenizer import ( - SecondaryStructureTokenizer, -) -from esm.tokenization.structure_tokenizer import ( - StructureTokenizer, -) +from esm.tokenization.function_tokenizer import InterProQuantizedTokenizer +from esm.tokenization.residue_tokenizer import ResidueAnnotationsTokenizer +from esm.tokenization.sasa_tokenizer import SASADiscretizingTokenizer +from esm.tokenization.sequence_tokenizer import EsmSequenceTokenizer +from esm.tokenization.ss_tokenizer import SecondaryStructureTokenizer +from esm.tokenization.structure_tokenizer import StructureTokenizer from esm.tokenization.tokenizer_base import EsmTokenizerBase from esm.utils.constants import api as api_constants from esm.utils.constants import esm3 as C @@ -251,6 +239,7 @@ def assemble_message(headers: Mapping[str, str], response: Response) -> dict[str content_type = headers.get("Content-Type", "application/json") if content_type == api_constants.MIMETYPE_ES_PICKLE: return pickle.loads(response.content) - elif content_type == "application/json": + elif "application/json" in content_type: + # Can handle something like "application/json; charset=utf-8" return response.json() raise ValueError(f"Unknown Content-Type: {content_type}") diff --git a/esm/utils/encoding.py b/esm/utils/encoding.py index 83c9d033..8461709d 100644 --- a/esm/utils/encoding.py +++ b/esm/utils/encoding.py @@ -7,26 +7,13 @@ from esm.tokenization.function_tokenizer import ( InterProQuantizedTokenizer as EsmFunctionTokenizer, ) - -from esm.tokenization.residue_tokenizer import ( - ResidueAnnotationsTokenizer, -) -from esm.tokenization.sasa_tokenizer import ( - SASADiscretizingTokenizer, -) -from esm.tokenization.sequence_tokenizer import ( - EsmSequenceTokenizer, -) -from esm.tokenization.ss_tokenizer import ( - SecondaryStructureTokenizer, -) -from esm.tokenization.structure_tokenizer import ( - StructureTokenizer, -) +from esm.tokenization.residue_tokenizer import ResidueAnnotationsTokenizer +from esm.tokenization.sasa_tokenizer import SASADiscretizingTokenizer +from esm.tokenization.sequence_tokenizer import EsmSequenceTokenizer +from esm.tokenization.ss_tokenizer import SecondaryStructureTokenizer +from esm.tokenization.structure_tokenizer import StructureTokenizer from esm.utils.constants import esm3 as C -from esm.utils.function.encode_decode import ( - encode_function_annotations, -) +from esm.utils.function.encode_decode import encode_function_annotations from esm.utils.structure.protein_chain import ProteinChain from esm.utils.types import FunctionAnnotation @@ -165,8 +152,6 @@ def tokenize_function_annotations( return function_tokens, residue_annotation_tokens - - # Tokenized Defaults def get_default_sequence_tokens( sequence_length: int, sequence_tokenizer: EsmSequenceTokenizer @@ -242,5 +227,3 @@ def get_default_residue_annotation_tokens( residue_annotation_tokens[0] = residue_annotation_tokenizer.bos_token_id residue_annotation_tokens[-1] = residue_annotation_tokenizer.eos_token_id return residue_annotation_tokens - - diff --git a/esm/utils/forge_context_manager.py b/esm/utils/forge_context_manager.py index bf898cd2..b1c2bdf3 100644 --- a/esm/utils/forge_context_manager.py +++ b/esm/utils/forge_context_manager.py @@ -7,10 +7,7 @@ from tqdm import tqdm from esm.sdk.api import ESMProteinError -from esm.sdk.forge import ( - retry_if_specific_error, - skip_retries_var, -) +from esm.sdk.retry import retry_if_specific_error, skip_retries_var TQDM_BAR_FORMAT = ( "{desc:<12}{percentage:3.0f}%|{bar:24}| {n_fmt}/{total_fmt} " @@ -25,7 +22,7 @@ def __init__( self, initial_concurrency: int = 32, min_concurrency: int = 1, - max_concurrency: int = 512, + max_concurrency: int = 64, step_up: int = 1, ): self.concurrency = initial_concurrency @@ -56,8 +53,10 @@ class ForgeBatchExecutor: """ def __init__( - self, max_attempts: int = 10, max_workers: int = 512, show_progress: bool = True + self, max_attempts: int = 10, max_workers: int = 64, show_progress: bool = True ): + if max_workers > 64: + raise ValueError("max_workers must be less than 64") self.rate_limiter = AIMDRateLimiter(max_concurrency=max_workers) self.max_attempts = max_attempts self.show_progress = show_progress diff --git a/esm/utils/function/encode_decode.py b/esm/utils/function/encode_decode.py index 29534e34..a4029858 100644 --- a/esm/utils/function/encode_decode.py +++ b/esm/utils/function/encode_decode.py @@ -3,16 +3,9 @@ import torch -from esm.models.function_decoder import ( - FunctionTokenDecoder, - merge_annotations, -) -from esm.tokenization.function_tokenizer import ( - InterProQuantizedTokenizer, -) -from esm.tokenization.residue_tokenizer import ( - ResidueAnnotationsTokenizer, -) +from esm.models.function_decoder import FunctionTokenDecoder, merge_annotations +from esm.tokenization.function_tokenizer import InterProQuantizedTokenizer +from esm.tokenization.residue_tokenizer import ResidueAnnotationsTokenizer from esm.utils.constants import esm3 as C from esm.utils.types import FunctionAnnotation diff --git a/esm/utils/function/lsh.py b/esm/utils/function/lsh.py index 25e8534c..87f4c674 100644 --- a/esm/utils/function/lsh.py +++ b/esm/utils/function/lsh.py @@ -65,7 +65,7 @@ def write_hyperplanes(self, filepath: PathLike): hyperplanes: dict[str, np.ndarray] = { # type: ignore str(i): table.hyperplanes for i, table in enumerate(self.tables) } - np.savez(filepath, **hyperplanes) + np.savez(filepath, **hyperplanes) # type: ignore def __call__(self, array): tokens = np.stack([table(array) for table in self.tables], 1) diff --git a/esm/utils/generation.py b/esm/utils/generation.py index 47c371b0..b2d4ede4 100644 --- a/esm/utils/generation.py +++ b/esm/utils/generation.py @@ -19,13 +19,8 @@ SamplingConfig, SamplingTrackConfig, ) -from esm.tokenization import ( - EsmTokenizerBase, - TokenizerCollectionProtocol, -) -from esm.tokenization.function_tokenizer import ( - InterProQuantizedTokenizer, -) +from esm.tokenization import EsmTokenizerBase, TokenizerCollectionProtocol +from esm.tokenization.function_tokenizer import InterProQuantizedTokenizer from esm.utils.constants import esm3 as C from esm.utils.misc import stack_variable_length_tensors from esm.utils.noise_schedules import NOISE_SCHEDULE_REGISTRY diff --git a/esm/utils/generation_test.py b/esm/utils/generation_test.py deleted file mode 100644 index f8f740bc..00000000 --- a/esm/utils/generation_test.py +++ /dev/null @@ -1,143 +0,0 @@ -import pytest -import torch - -from evolutionaryscale.models.esm3v2 import Esm3v2 -from esm.sdk.api import ( - ESMProtein, - ESMProteinTensor, - GenerationConfig, -) -from evolutionaryscale.utils.env import ModelName -from evolutionaryscale.utils.remote_inference.api_v1 import ( - ESM3RemoteModelInferenceClient, -) -from projects.forge.inference.utils.model import _load_esm_model - - -@pytest.fixture() -def esm3_remote_inference_client(): - model = _load_esm_model( - ModelName.ESM3_TINY_DEV, distributed_model=False, load_function_decoder=False - ) - assert isinstance(model, Esm3v2) - client = ESM3RemoteModelInferenceClient( - model, - tokenizers=model.tokenizers, - device=torch.device("cuda"), - enable_batched_runner=False, - ) - return client - - -@pytest.mark.gpu -def test_chain_break_tokens(esm3_remote_inference_client): - tokenizer = esm3_remote_inference_client.tokenizers.sequence - # 3 separate chains with 2 chainbreak tokens. - sequence_with_chain_breaks = torch.tensor( - [ - tokenizer.bos_token_id, - 20, - 20, - 20, - 20, - tokenizer.chain_break_token_id, - 21, - 21, - 21, - tokenizer.chain_break_token_id, - 22, - 22, - 22, - tokenizer.eos_token_id, - ] - ) - protein = esm3_remote_inference_client.generate( - ESMProteinTensor(sequence=sequence_with_chain_breaks), - # There are 10 tokens that actually need to be sampled. - GenerationConfig(track="structure", num_steps=10), - ) - - assert isinstance(protein, ESMProteinTensor) - assert protein.structure is not None - - -@pytest.mark.gpu -def test_num_decoding_steps_more_than_mask_tokens(esm3_remote_inference_client): - protein = esm3_remote_inference_client.generate( - esm3_remote_inference_client.encode( - ESMProtein(sequence="CDEFG") - ), # sequence of 5. - GenerationConfig(track="structure", num_steps=10), # use 10 decoding steps. - ) - # Client should handle over-specification of decoding steps. - # TODO: This should be a warning. - assert isinstance(protein, ESMProteinTensor) - assert protein.structure is not None - - -@pytest.mark.gpu -def test_num_decoding_steps_more_than_mask_tokens_batched(esm3_remote_inference_client): - protein_list = esm3_remote_inference_client.batch_generate( - inputs=[ - esm3_remote_inference_client.encode(ESMProtein(sequence="CDEFG")), - esm3_remote_inference_client.encode(ESMProtein(sequence="ABCDEFG")), - esm3_remote_inference_client.encode(ESMProtein(sequence="AB__EFG")), - ], - configs=[ - GenerationConfig(track="structure", num_steps=10), - GenerationConfig(track="structure", num_steps=3), - GenerationConfig(track="sequence", num_steps=20), - ], - ) - # Client should handle over-specification of decoding steps. - # TODO: This should be a warning. - assert isinstance(protein_list[0], ESMProteinTensor) - assert protein_list[0].structure is not None - assert isinstance(protein_list[1], ESMProteinTensor) - assert protein_list[1].structure is not None - assert isinstance(protein_list[2], ESMProteinTensor) - assert protein_list[2].sequence is not None - - -@pytest.mark.gpu -def test_encode_chainbreak_token(esm3_remote_inference_client): - protein = esm3_remote_inference_client.encode(ESMProtein(sequence="MSTNP|KPQKK")) - assert isinstance(protein, ESMProteinTensor) - assert protein.sequence is not None - assert ( - protein.sequence[6] - == esm3_remote_inference_client.tokenizers.sequence.chain_break_token_id - ) - - -@pytest.mark.gpu -def test_generation_with_chainbreak_token(esm3_remote_inference_client): - chainbreak_sequence = torch.tensor( - [ - esm3_remote_inference_client.tokenizers.sequence.bos_token_id, - 20, - 8, - 11, - 17, - 14, - esm3_remote_inference_client.tokenizers.sequence.chain_break_token_id, - 15, - 14, - 16, - 15, - 15, - esm3_remote_inference_client.tokenizers.sequence.eos_token_id, - ] - ) - - protein = esm3_remote_inference_client.generate( - ESMProteinTensor(sequence=chainbreak_sequence), - GenerationConfig(track="structure", num_steps=1), - ) - # Can't specify more decoding steps than masks available. - assert isinstance(protein, ESMProteinTensor) - assert protein.structure is not None - assert ( - protein.structure[6] - == esm3_remote_inference_client.tokenizers.structure.chain_break_token_id - ) diff --git a/esm/utils/misc.py b/esm/utils/misc.py index 0afb9a1f..f0d7a602 100644 --- a/esm/utils/misc.py +++ b/esm/utils/misc.py @@ -33,15 +33,15 @@ def slice_python_object_as_numpy( >>> slice_python_object_as_numpy(obj, np.arange(5) < 3) [1, 2, 3] """ - if isinstance(idx, int): - idx = [idx] + if np.isscalar(idx): + idx = [int(idx)] # type: ignore if isinstance(idx, np.ndarray) and idx.dtype == bool: sliced_obj = [obj[i] for i in np.where(idx)[0]] elif isinstance(idx, slice): sliced_obj = obj[idx] else: - sliced_obj = [obj[i] for i in idx] + sliced_obj = [obj[i] for i in idx] # type: ignore match obj, sliced_obj: case str(), list(): @@ -156,6 +156,37 @@ def stack_variable_length_tensors( return array +def binpack( + tensor: torch.Tensor, sequence_id: torch.Tensor | None, pad_value: int | float +): + """ + Args: + tensor (Tensor): [B, L, ...] + + Returns: + Tensor: [B_binpacked, L_binpacked, ...] + """ + if sequence_id is None: + return tensor + + num_sequences = sequence_id.max(dim=-1).values + 1 + + dims = sequence_id.shape + tensor.shape[2:] + output_tensor = torch.full( + dims, fill_value=pad_value, dtype=tensor.dtype, device=tensor.device + ) + + idx = 0 + for batch_idx, (batch_seqid, batch_num_sequences) in enumerate( + zip(sequence_id, num_sequences) + ): + for seqid in range(batch_num_sequences): + mask = batch_seqid == seqid + output_tensor[batch_idx, mask] = tensor[idx, : mask.sum()] + idx += 1 + return output_tensor + + def unbinpack( tensor: torch.Tensor, sequence_id: torch.Tensor | None, pad_value: int | float ): @@ -280,9 +311,18 @@ def maybe_list(x, convert_nan_to_none: bool = False) -> list | None: return None if not convert_nan_to_none: return x.tolist() - nan_mask = torch.isnan(x) - np_arr = x.cpu().numpy().astype(object) - np_arr[nan_mask.cpu().numpy()] = None + + # Handle both torch.tensor and np.ndarray input. + if isinstance(x, torch.Tensor): + nan_mask = torch.isnan(x).cpu().numpy() + np_arr = x.cpu().numpy().astype(object) + elif isinstance(x, np.ndarray): + nan_mask = np.isnan(x) + np_arr = x.astype(object) + else: + raise TypeError("maybe_list can only work with torch.tensor or np.ndarray.") + + np_arr[nan_mask] = None return np_arr.tolist() @@ -313,7 +353,6 @@ def get_chainbreak_boundaries_from_sequence(sequence: Sequence[str]) -> np.ndarr return chain_boundaries -# TODO(return_bytes): remove when retiring return_bytes on SageMaker def deserialize_tensors(b: bytes) -> Any: buf = BytesIO(zstd.ZSTD_uncompress(b)) d = torch.load(buf, map_location="cpu", weights_only=False) diff --git a/esm/utils/residue_constants.py b/esm/utils/residue_constants.py index b1af5390..81b379e8 100644 --- a/esm/utils/residue_constants.py +++ b/esm/utils/residue_constants.py @@ -1,3 +1,4 @@ +# Copyright 2025 EvolutionaryScale # Copyright 2021 AlQuraishi Laboratory # Copyright 2021 DeepMind Technologies Limited # @@ -13,6 +14,527 @@ # See the License for the specific language governing permissions and # limitations under the License. +"""Constants used in AlphaFold.""" + +import collections +import functools +from pathlib import Path +from typing import List, Mapping, Tuple + +import numpy as np + +# import tree + +# Internal import (35fd). + + +# Distance from one CA to next CA [trans configuration: omega = 180]. +ca_ca = 3.80209737096 + +# Format: The list for each AA type contains chi1, chi2, chi3, chi4 in +# this order (or a relevant subset from chi1 onwards). ALA and GLY don't have +# chi angles so their chi angle lists are empty. +chi_angles_atoms = { + "ALA": [], + # Chi5 in arginine is always 0 +- 5 degrees, so ignore it. + "ARG": [ + ["N", "CA", "CB", "CG"], + ["CA", "CB", "CG", "CD"], + ["CB", "CG", "CD", "NE"], + ["CG", "CD", "NE", "CZ"], + ], + "ASN": [["N", "CA", "CB", "CG"], ["CA", "CB", "CG", "OD1"]], + "ASP": [["N", "CA", "CB", "CG"], ["CA", "CB", "CG", "OD1"]], + "CYS": [["N", "CA", "CB", "SG"]], + "GLN": [ + ["N", "CA", "CB", "CG"], + ["CA", "CB", "CG", "CD"], + ["CB", "CG", "CD", "OE1"], + ], + "GLU": [ + ["N", "CA", "CB", "CG"], + ["CA", "CB", "CG", "CD"], + ["CB", "CG", "CD", "OE1"], + ], + "GLY": [], + "HIS": [["N", "CA", "CB", "CG"], ["CA", "CB", "CG", "ND1"]], + "ILE": [["N", "CA", "CB", "CG1"], ["CA", "CB", "CG1", "CD1"]], + "LEU": [["N", "CA", "CB", "CG"], ["CA", "CB", "CG", "CD1"]], + "LYS": [ + ["N", "CA", "CB", "CG"], + ["CA", "CB", "CG", "CD"], + ["CB", "CG", "CD", "CE"], + ["CG", "CD", "CE", "NZ"], + ], + "MET": [ + ["N", "CA", "CB", "CG"], + ["CA", "CB", "CG", "SD"], + ["CB", "CG", "SD", "CE"], + ], + "PHE": [["N", "CA", "CB", "CG"], ["CA", "CB", "CG", "CD1"]], + "PRO": [["N", "CA", "CB", "CG"], ["CA", "CB", "CG", "CD"]], + "SER": [["N", "CA", "CB", "OG"]], + "THR": [["N", "CA", "CB", "OG1"]], + "TRP": [["N", "CA", "CB", "CG"], ["CA", "CB", "CG", "CD1"]], + "TYR": [["N", "CA", "CB", "CG"], ["CA", "CB", "CG", "CD1"]], + "VAL": [["N", "CA", "CB", "CG1"]], + "UNK": [], +} + +# If chi angles given in fixed-length array, this matrix determines how to mask +# them for each AA type. The order is as per restype_order (see below). +chi_angles_mask = [ + [0.0, 0.0, 0.0, 0.0], # ALA + [1.0, 1.0, 1.0, 1.0], # ARG + [1.0, 1.0, 0.0, 0.0], # ASN + [1.0, 1.0, 0.0, 0.0], # ASP + [1.0, 0.0, 0.0, 0.0], # CYS + [1.0, 1.0, 1.0, 0.0], # GLN + [1.0, 1.0, 1.0, 0.0], # GLU + [0.0, 0.0, 0.0, 0.0], # GLY + [1.0, 1.0, 0.0, 0.0], # HIS + [1.0, 1.0, 0.0, 0.0], # ILE + [1.0, 1.0, 0.0, 0.0], # LEU + [1.0, 1.0, 1.0, 1.0], # LYS + [1.0, 1.0, 1.0, 0.0], # MET + [1.0, 1.0, 0.0, 0.0], # PHE + [1.0, 1.0, 0.0, 0.0], # PRO + [1.0, 0.0, 0.0, 0.0], # SER + [1.0, 0.0, 0.0, 0.0], # THR + [1.0, 1.0, 0.0, 0.0], # TRP + [1.0, 1.0, 0.0, 0.0], # TYR + [1.0, 0.0, 0.0, 0.0], # VAL + [0.0, 0.0, 0.0, 0.0], # UNK +] + +# The following chi angles are pi periodic: they can be rotated by a multiple +# of pi without affecting the structure. +chi_pi_periodic = [ + [0.0, 0.0, 0.0, 0.0], # ALA + [0.0, 0.0, 0.0, 0.0], # ARG + [0.0, 0.0, 0.0, 0.0], # ASN + [0.0, 1.0, 0.0, 0.0], # ASP + [0.0, 0.0, 0.0, 0.0], # CYS + [0.0, 0.0, 0.0, 0.0], # GLN + [0.0, 0.0, 1.0, 0.0], # GLU + [0.0, 0.0, 0.0, 0.0], # GLY + [0.0, 0.0, 0.0, 0.0], # HIS + [0.0, 0.0, 0.0, 0.0], # ILE + [0.0, 0.0, 0.0, 0.0], # LEU + [0.0, 0.0, 0.0, 0.0], # LYS + [0.0, 0.0, 0.0, 0.0], # MET + [0.0, 1.0, 0.0, 0.0], # PHE + [0.0, 0.0, 0.0, 0.0], # PRO + [0.0, 0.0, 0.0, 0.0], # SER + [0.0, 0.0, 0.0, 0.0], # THR + [0.0, 0.0, 0.0, 0.0], # TRP + [0.0, 1.0, 0.0, 0.0], # TYR + [0.0, 0.0, 0.0, 0.0], # VAL + [0.0, 0.0, 0.0, 0.0], # UNK +] + +# Atoms positions relative to the 8 rigid groups, defined by the pre-omega, phi, +# psi and chi angles: +# 0: 'backbone group', +# 1: 'pre-omega-group', (empty) +# 2: 'phi-group', (currently empty, because it defines only hydrogens) +# 3: 'psi-group', +# 4,5,6,7: 'chi1,2,3,4-group' +# The atom positions are relative to the axis-end-atom of the corresponding +# rotation axis. The x-axis is in direction of the rotation axis, and the y-axis +# is defined such that the dihedral-angle-definiting atom (the last entry in +# chi_angles_atoms above) is in the xy-plane (with a positive y-coordinate). +# format: [atomname, group_idx, rel_position] +rigid_group_atom_positions = { + "ALA": [ + ["N", 0, (-0.525, 1.363, 0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.526, -0.000, -0.000)], + ["CB", 0, (-0.529, -0.774, -1.205)], + ["O", 3, (0.627, 1.062, 0.000)], + ], + "ARG": [ + ["N", 0, (-0.524, 1.362, -0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.525, -0.000, -0.000)], + ["CB", 0, (-0.524, -0.778, -1.209)], + ["O", 3, (0.626, 1.062, 0.000)], + ["CG", 4, (0.616, 1.390, -0.000)], + ["CD", 5, (0.564, 1.414, 0.000)], + ["NE", 6, (0.539, 1.357, -0.000)], + ["NH1", 7, (0.206, 2.301, 0.000)], + ["NH2", 7, (2.078, 0.978, -0.000)], + ["CZ", 7, (0.758, 1.093, -0.000)], + ], + "ASN": [ + ["N", 0, (-0.536, 1.357, 0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.526, -0.000, -0.000)], + ["CB", 0, (-0.531, -0.787, -1.200)], + ["O", 3, (0.625, 1.062, 0.000)], + ["CG", 4, (0.584, 1.399, 0.000)], + ["ND2", 5, (0.593, -1.188, 0.001)], + ["OD1", 5, (0.633, 1.059, 0.000)], + ], + "ASP": [ + ["N", 0, (-0.525, 1.362, -0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.527, 0.000, -0.000)], + ["CB", 0, (-0.526, -0.778, -1.208)], + ["O", 3, (0.626, 1.062, -0.000)], + ["CG", 4, (0.593, 1.398, -0.000)], + ["OD1", 5, (0.610, 1.091, 0.000)], + ["OD2", 5, (0.592, -1.101, -0.003)], + ], + "CYS": [ + ["N", 0, (-0.522, 1.362, -0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.524, 0.000, 0.000)], + ["CB", 0, (-0.519, -0.773, -1.212)], + ["O", 3, (0.625, 1.062, -0.000)], + ["SG", 4, (0.728, 1.653, 0.000)], + ], + "GLN": [ + ["N", 0, (-0.526, 1.361, -0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.526, 0.000, 0.000)], + ["CB", 0, (-0.525, -0.779, -1.207)], + ["O", 3, (0.626, 1.062, -0.000)], + ["CG", 4, (0.615, 1.393, 0.000)], + ["CD", 5, (0.587, 1.399, -0.000)], + ["NE2", 6, (0.593, -1.189, -0.001)], + ["OE1", 6, (0.634, 1.060, 0.000)], + ], + "GLU": [ + ["N", 0, (-0.528, 1.361, 0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.526, -0.000, -0.000)], + ["CB", 0, (-0.526, -0.781, -1.207)], + ["O", 3, (0.626, 1.062, 0.000)], + ["CG", 4, (0.615, 1.392, 0.000)], + ["CD", 5, (0.600, 1.397, 0.000)], + ["OE1", 6, (0.607, 1.095, -0.000)], + ["OE2", 6, (0.589, -1.104, -0.001)], + ], + "GLY": [ + ["N", 0, (-0.572, 1.337, 0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.517, -0.000, -0.000)], + ["O", 3, (0.626, 1.062, -0.000)], + ], + "HIS": [ + ["N", 0, (-0.527, 1.360, 0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.525, 0.000, 0.000)], + ["CB", 0, (-0.525, -0.778, -1.208)], + ["O", 3, (0.625, 1.063, 0.000)], + ["CG", 4, (0.600, 1.370, -0.000)], + ["CD2", 5, (0.889, -1.021, 0.003)], + ["ND1", 5, (0.744, 1.160, -0.000)], + ["CE1", 5, (2.030, 0.851, 0.002)], + ["NE2", 5, (2.145, -0.466, 0.004)], + ], + "ILE": [ + ["N", 0, (-0.493, 1.373, -0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.527, -0.000, -0.000)], + ["CB", 0, (-0.536, -0.793, -1.213)], + ["O", 3, (0.627, 1.062, -0.000)], + ["CG1", 4, (0.534, 1.437, -0.000)], + ["CG2", 4, (0.540, -0.785, -1.199)], + ["CD1", 5, (0.619, 1.391, 0.000)], + ], + "LEU": [ + ["N", 0, (-0.520, 1.363, 0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.525, -0.000, -0.000)], + ["CB", 0, (-0.522, -0.773, -1.214)], + ["O", 3, (0.625, 1.063, -0.000)], + ["CG", 4, (0.678, 1.371, 0.000)], + ["CD1", 5, (0.530, 1.430, -0.000)], + ["CD2", 5, (0.535, -0.774, 1.200)], + ], + "LYS": [ + ["N", 0, (-0.526, 1.362, -0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.526, 0.000, 0.000)], + ["CB", 0, (-0.524, -0.778, -1.208)], + ["O", 3, (0.626, 1.062, -0.000)], + ["CG", 4, (0.619, 1.390, 0.000)], + ["CD", 5, (0.559, 1.417, 0.000)], + ["CE", 6, (0.560, 1.416, 0.000)], + ["NZ", 7, (0.554, 1.387, 0.000)], + ], + "MET": [ + ["N", 0, (-0.521, 1.364, -0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.525, 0.000, 0.000)], + ["CB", 0, (-0.523, -0.776, -1.210)], + ["O", 3, (0.625, 1.062, -0.000)], + ["CG", 4, (0.613, 1.391, -0.000)], + ["SD", 5, (0.703, 1.695, 0.000)], + ["CE", 6, (0.320, 1.786, -0.000)], + ], + "PHE": [ + ["N", 0, (-0.518, 1.363, 0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.524, 0.000, -0.000)], + ["CB", 0, (-0.525, -0.776, -1.212)], + ["O", 3, (0.626, 1.062, -0.000)], + ["CG", 4, (0.607, 1.377, 0.000)], + ["CD1", 5, (0.709, 1.195, -0.000)], + ["CD2", 5, (0.706, -1.196, 0.000)], + ["CE1", 5, (2.102, 1.198, -0.000)], + ["CE2", 5, (2.098, -1.201, -0.000)], + ["CZ", 5, (2.794, -0.003, -0.001)], + ], + "PRO": [ + ["N", 0, (-0.566, 1.351, -0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.527, -0.000, 0.000)], + ["CB", 0, (-0.546, -0.611, -1.293)], + ["O", 3, (0.621, 1.066, 0.000)], + ["CG", 4, (0.382, 1.445, 0.0)], + # ['CD', 5, (0.427, 1.440, 0.0)], + ["CD", 5, (0.477, 1.424, 0.0)], # manually made angle 2 degrees larger + ], + "SER": [ + ["N", 0, (-0.529, 1.360, -0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.525, -0.000, -0.000)], + ["CB", 0, (-0.518, -0.777, -1.211)], + ["O", 3, (0.626, 1.062, -0.000)], + ["OG", 4, (0.503, 1.325, 0.000)], + ], + "THR": [ + ["N", 0, (-0.517, 1.364, 0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.526, 0.000, -0.000)], + ["CB", 0, (-0.516, -0.793, -1.215)], + ["O", 3, (0.626, 1.062, 0.000)], + ["CG2", 4, (0.550, -0.718, -1.228)], + ["OG1", 4, (0.472, 1.353, 0.000)], + ], + "TRP": [ + ["N", 0, (-0.521, 1.363, 0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.525, -0.000, 0.000)], + ["CB", 0, (-0.523, -0.776, -1.212)], + ["O", 3, (0.627, 1.062, 0.000)], + ["CG", 4, (0.609, 1.370, -0.000)], + ["CD1", 5, (0.824, 1.091, 0.000)], + ["CD2", 5, (0.854, -1.148, -0.005)], + ["CE2", 5, (2.186, -0.678, -0.007)], + ["CE3", 5, (0.622, -2.530, -0.007)], + ["NE1", 5, (2.140, 0.690, -0.004)], + ["CH2", 5, (3.028, -2.890, -0.013)], + ["CZ2", 5, (3.283, -1.543, -0.011)], + ["CZ3", 5, (1.715, -3.389, -0.011)], + ], + "TYR": [ + ["N", 0, (-0.522, 1.362, 0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.524, -0.000, -0.000)], + ["CB", 0, (-0.522, -0.776, -1.213)], + ["O", 3, (0.627, 1.062, -0.000)], + ["CG", 4, (0.607, 1.382, -0.000)], + ["CD1", 5, (0.716, 1.195, -0.000)], + ["CD2", 5, (0.713, -1.194, -0.001)], + ["CE1", 5, (2.107, 1.200, -0.002)], + ["CE2", 5, (2.104, -1.201, -0.003)], + ["OH", 5, (4.168, -0.002, -0.005)], + ["CZ", 5, (2.791, -0.001, -0.003)], + ], + "VAL": [ + ["N", 0, (-0.494, 1.373, -0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.527, -0.000, -0.000)], + ["CB", 0, (-0.533, -0.795, -1.213)], + ["O", 3, (0.627, 1.062, -0.000)], + ["CG1", 4, (0.540, 1.429, -0.000)], + ["CG2", 4, (0.533, -0.776, 1.203)], + ], + # Assume alanine positions for unknown AA + "UNK": [ + ["N", 0, (-0.525, 1.363, 0.000)], + ["CA", 0, (0.000, 0.000, 0.000)], + ["C", 0, (1.526, -0.000, -0.000)], + ], +} + +# A list of atoms (excluding hydrogen) for each AA type. PDB naming convention. +residue_atoms = { + "ALA": ["C", "CA", "CB", "N", "O"], + "ARG": ["C", "CA", "CB", "CG", "CD", "CZ", "N", "NE", "O", "NH1", "NH2"], + "ASP": ["C", "CA", "CB", "CG", "N", "O", "OD1", "OD2"], + "ASN": ["C", "CA", "CB", "CG", "N", "ND2", "O", "OD1"], + "CYS": ["C", "CA", "CB", "N", "O", "SG"], + "GLU": ["C", "CA", "CB", "CG", "CD", "N", "O", "OE1", "OE2"], + "GLN": ["C", "CA", "CB", "CG", "CD", "N", "NE2", "O", "OE1"], + "GLY": ["C", "CA", "N", "O"], + "HIS": ["C", "CA", "CB", "CG", "CD2", "CE1", "N", "ND1", "NE2", "O"], + "ILE": ["C", "CA", "CB", "CG1", "CG2", "CD1", "N", "O"], + "LEU": ["C", "CA", "CB", "CG", "CD1", "CD2", "N", "O"], + "LYS": ["C", "CA", "CB", "CG", "CD", "CE", "N", "NZ", "O"], + "MET": ["C", "CA", "CB", "CG", "CE", "N", "O", "SD"], + "PHE": ["C", "CA", "CB", "CG", "CD1", "CD2", "CE1", "CE2", "CZ", "N", "O"], + "PRO": ["C", "CA", "CB", "CG", "CD", "N", "O"], + "SER": ["C", "CA", "CB", "N", "O", "OG"], + "THR": ["C", "CA", "CB", "CG2", "N", "O", "OG1"], + "TRP": [ + "C", + "CA", + "CB", + "CG", + "CD1", + "CD2", + "CE2", + "CE3", + "CZ2", + "CZ3", + "CH2", + "N", + "NE1", + "O", + ], + "TYR": ["C", "CA", "CB", "CG", "CD1", "CD2", "CE1", "CE2", "CZ", "N", "O", "OH"], + "VAL": ["C", "CA", "CB", "CG1", "CG2", "N", "O"], + "UNK": ["C", "CA", "N"], +} + +# Naming swaps for ambiguous atom names. +# Due to symmetries in the amino acids the naming of atoms is ambiguous in +# 4 of the 20 amino acids. +# (The LDDT paper lists 7 amino acids as ambiguous, but the naming ambiguities +# in LEU, VAL and ARG can be resolved by using the 3d constellations of +# the 'ambiguous' atoms and their neighbours) +# TODO: ^ interpret this +residue_atom_renaming_swaps = { + "ASP": {"OD1": "OD2"}, + "GLU": {"OE1": "OE2"}, + "PHE": {"CD1": "CD2", "CE1": "CE2"}, + "TYR": {"CD1": "CD2", "CE1": "CE2"}, +} + +# Van der Waals radii [Angstroem] of the atoms (from Wikipedia) +van_der_waals_radius = {"C": 1.7, "N": 1.55, "O": 1.52, "S": 1.8} + +Bond = collections.namedtuple("Bond", ["atom1_name", "atom2_name", "length", "stddev"]) +BondAngle = collections.namedtuple( + "BondAngle", ["atom1_name", "atom2_name", "atom3name", "angle_rad", "stddev"] +) + + +@functools.lru_cache(maxsize=None) +def load_stereo_chemical_props() -> ( + Tuple[ + Mapping[str, List[Bond]], + Mapping[str, List[Bond]], + Mapping[str, List[BondAngle]], + ] +): + """Load stereo_chemical_props.txt into a nice structure. + + Load literature values for bond lengths and bond angles and translate + bond angles into the length of the opposite edge of the triangle + ("residue_virtual_bonds"). + + Returns: + residue_bonds: dict that maps resname --> list of Bond tuples + residue_virtual_bonds: dict that maps resname --> list of Bond tuples + residue_bond_angles: dict that maps resname --> list of BondAngle tuples + """ + stereo_chemical_props = Path( + "evolutionaryscale/structure/stereo_chemical_props.txt" + ).read_text() + + lines_iter = iter(stereo_chemical_props.splitlines()) + # Load bond lengths. + residue_bonds = {} + next(lines_iter) # Skip header line. + for line in lines_iter: + if line.strip() == "-": + break + bond, resname, length, stddev = line.split() + atom1, atom2 = bond.split("-") + if resname not in residue_bonds: + residue_bonds[resname] = [] + residue_bonds[resname].append(Bond(atom1, atom2, float(length), float(stddev))) + residue_bonds["UNK"] = [] + + # Load bond angles. + residue_bond_angles = {} + next(lines_iter) # Skip empty line. + next(lines_iter) # Skip header line. + for line in lines_iter: + if line.strip() == "-": + break + bond, resname, angle_degree, stddev_degree = line.split() + atom1, atom2, atom3 = bond.split("-") + if resname not in residue_bond_angles: + residue_bond_angles[resname] = [] + residue_bond_angles[resname].append( + BondAngle( + atom1, + atom2, + atom3, + float(angle_degree) / 180.0 * np.pi, + float(stddev_degree) / 180.0 * np.pi, + ) + ) + residue_bond_angles["UNK"] = [] + + def make_bond_key(atom1_name, atom2_name): + """Unique key to lookup bonds.""" + return "-".join(sorted([atom1_name, atom2_name])) + + # Translate bond angles into distances ("virtual bonds"). + residue_virtual_bonds = {} + for resname, bond_angles in residue_bond_angles.items(): + # Create a fast lookup dict for bond lengths. + bond_cache = {} + for b in residue_bonds[resname]: + bond_cache[make_bond_key(b.atom1_name, b.atom2_name)] = b + residue_virtual_bonds[resname] = [] + for ba in bond_angles: + bond1 = bond_cache[make_bond_key(ba.atom1_name, ba.atom2_name)] + bond2 = bond_cache[make_bond_key(ba.atom2_name, ba.atom3name)] + + # Compute distance between atom1 and atom3 using the law of cosines + # c^2 = a^2 + b^2 - 2ab*cos(gamma). + gamma = ba.angle_rad + length = np.sqrt( + bond1.length**2 + + bond2.length**2 + - 2 * bond1.length * bond2.length * np.cos(gamma) + ) + + # Propagation of uncertainty assuming uncorrelated errors. + dl_outer = 0.5 / length + dl_dgamma = (2 * bond1.length * bond2.length * np.sin(gamma)) * dl_outer + dl_db1 = (2 * bond1.length - 2 * bond2.length * np.cos(gamma)) * dl_outer + dl_db2 = (2 * bond2.length - 2 * bond1.length * np.cos(gamma)) * dl_outer + stddev = np.sqrt( + (dl_dgamma * ba.stddev) ** 2 + + (dl_db1 * bond1.stddev) ** 2 + + (dl_db2 * bond2.stddev) ** 2 + ) + residue_virtual_bonds[resname].append( + Bond(ba.atom1_name, ba.atom3name, length, stddev) + ) + + return (residue_bonds, residue_virtual_bonds, residue_bond_angles) + + +# Between-residue bond lengths for general bonds (first element) and for Proline +# (second element). +between_res_bond_length_c_n = [1.329, 1.341] +between_res_bond_length_stddev_c_n = [0.014, 0.016] + +# Between-residue cos_angles. +between_res_cos_angles_c_n_ca = [-0.5203, 0.0353] # degrees: 121.352 +- 2.315 +between_res_cos_angles_ca_c_n = [-0.4473, 0.0311] # degrees: 116.568 +- 1.995 + # This mapping is used when we need to store atom data in a format that requires # fixed atom data size for every residue (e.g. a numpy array). atom_types = [ @@ -57,27 +579,190 @@ atom_order = {atom_type: i for i, atom_type in enumerate(atom_types)} atom_type_num = len(atom_types) # := 37. -restype_1to3 = { - "A": "ALA", - "R": "ARG", - "N": "ASN", - "D": "ASP", - "C": "CYS", - "Q": "GLN", - "E": "GLU", - "G": "GLY", - "H": "HIS", - "I": "ILE", - "L": "LEU", - "K": "LYS", - "M": "MET", - "F": "PHE", - "P": "PRO", - "S": "SER", - "T": "THR", - "W": "TRP", - "Y": "TYR", - "V": "VAL", +# A compact atom encoding with 14 columns +# pylint: disable=line-too-long +# pylint: disable=bad-whitespace +restype_name_to_atom14_names = { + "ALA": ["N", "CA", "C", "O", "CB", "", "", "", "", "", "", "", "", ""], + "ARG": [ + "N", + "CA", + "C", + "O", + "CB", + "CG", + "CD", + "NE", + "CZ", + "NH1", + "NH2", + "", + "", + "", + ], + "ASN": ["N", "CA", "C", "O", "CB", "CG", "OD1", "ND2", "", "", "", "", "", ""], + "ASP": ["N", "CA", "C", "O", "CB", "CG", "OD1", "OD2", "", "", "", "", "", ""], + "CYS": ["N", "CA", "C", "O", "CB", "SG", "", "", "", "", "", "", "", ""], + "GLN": ["N", "CA", "C", "O", "CB", "CG", "CD", "OE1", "NE2", "", "", "", "", ""], + "GLU": ["N", "CA", "C", "O", "CB", "CG", "CD", "OE1", "OE2", "", "", "", "", ""], + "GLY": ["N", "CA", "C", "O", "", "", "", "", "", "", "", "", "", ""], + "HIS": [ + "N", + "CA", + "C", + "O", + "CB", + "CG", + "ND1", + "CD2", + "CE1", + "NE2", + "", + "", + "", + "", + ], + "ILE": ["N", "CA", "C", "O", "CB", "CG1", "CG2", "CD1", "", "", "", "", "", ""], + "LEU": ["N", "CA", "C", "O", "CB", "CG", "CD1", "CD2", "", "", "", "", "", ""], + "LYS": ["N", "CA", "C", "O", "CB", "CG", "CD", "CE", "NZ", "", "", "", "", ""], + "MET": ["N", "CA", "C", "O", "CB", "CG", "SD", "CE", "", "", "", "", "", ""], + "PHE": [ + "N", + "CA", + "C", + "O", + "CB", + "CG", + "CD1", + "CD2", + "CE1", + "CE2", + "CZ", + "", + "", + "", + ], + "PRO": ["N", "CA", "C", "O", "CB", "CG", "CD", "", "", "", "", "", "", ""], + "SER": ["N", "CA", "C", "O", "CB", "OG", "", "", "", "", "", "", "", ""], + "THR": ["N", "CA", "C", "O", "CB", "OG1", "CG2", "", "", "", "", "", "", ""], + "TRP": [ + "N", + "CA", + "C", + "O", + "CB", + "CG", + "CD1", + "CD2", + "NE1", + "CE2", + "CE3", + "CZ2", + "CZ3", + "CH2", + ], + "TYR": [ + "N", + "CA", + "C", + "O", + "CB", + "CG", + "CD1", + "CD2", + "CE1", + "CE2", + "CZ", + "OH", + "", + "", + ], + "VAL": ["N", "CA", "C", "O", "CB", "CG1", "CG2", "", "", "", "", "", "", ""], + "UNK": ["N", "CA", "C", "", "", "", "", "", "", "", "", "", "", ""], +} +# pylint: enable=line-too-long +# pylint: enable=bad-whitespace + + +# This is the standard residue order when coding AA type as a number. +# Reproduce it by taking 3-letter AA codes and sorting them alphabetically. +restypes = [ + "A", + "R", + "N", + "D", + "C", + "Q", + "E", + "G", + "H", + "I", + "L", + "K", + "M", + "F", + "P", + "S", + "T", + "W", + "Y", + "V", +] +restype_order = {restype: i for i, restype in enumerate(restypes)} +restype_num = len(restypes) # := 20. +unk_restype_index = restype_num # Catch-all index for unknown restypes. + +restypes_with_x = restypes + ["X"] +restype_order_with_x = {restype: i for i, restype in enumerate(restypes_with_x)} + +bb_atoms = ["N", "CA", "C", "O"] + +# Hydrophobicity by residue (positive values are hydrophobic). Derived from Black & Mould (1991), normalized by subtracting 0.5. +hydrophobicity = { + "ALA": 0.116, + "ARG": -0.5, + "ASN": -0.264, + "ASP": -0.472, + "CYS": 0.18, + "GLN": -0.249, + "GLU": -0.457, + "GLY": 0.001, + "HIS": -0.335, + "ILE": 0.443, + "LEU": 0.443, + "LYS": -0.217, + "MET": 0.238, + "PHE": 0.5, + "PRO": 0.211, + "SER": -0.141, + "THR": -0.05, + "TRP": 0.378, + "TYR": 0.38, + "VAL": 0.325, +} + +# Side chain max accessible surface area in Ala-X-Ala tripeptide (from Chennamsetty et al. 2010). +side_chain_asa = { + "ALA": 64.7809, + "ARG": 210.02, + "ASN": 113.187, + "ASP": 110.209, + "CYS": 95.2439, + "GLN": 147.855, + "GLU": 143.924, + "GLY": 23.1338, + "HIS": 146.449, + "ILE": 151.242, + "LEU": 139.524, + "LYS": 177.366, + "MET": 164.674, + "PHE": 186.7, + "PRO": 111.533, + "SER": 81.2159, + "THR": 111.597, + "TRP": 229.619, + "TYR": 200.306, + "VAL": 124.237, } # Approximate Volumes of amino acids in cubic angstroms. @@ -105,3 +790,434 @@ "V": 140.0, # Valine "X": 88.6, # Unknown, use Alanine as approximation } + + +def sequence_to_onehot( + sequence: str, mapping: Mapping[str, int], map_unknown_to_x: bool = False +) -> np.ndarray: + """Maps the given sequence into a one-hot encoded matrix. + + Args: + sequence: An amino acid sequence. + mapping: A dictionary mapping amino acids to integers. + map_unknown_to_x: If True, any amino acid that is not in the mapping will be + mapped to the unknown amino acid 'X'. If the mapping doesn't contain + amino acid 'X', an error will be thrown. If False, any amino acid not in + the mapping will throw an error. + + Returns: + A numpy array of shape (seq_len, num_unique_aas) with one-hot encoding of + the sequence. + + Raises: + ValueError: If the mapping doesn't contain values from 0 to + num_unique_aas - 1 without any gaps. + """ + num_entries = max(mapping.values()) + 1 + + if sorted(set(mapping.values())) != list(range(num_entries)): + raise ValueError( + "The mapping must have values from 0 to num_unique_aas-1 " + "without any gaps. Got: %s" % sorted(mapping.values()) + ) + + one_hot_arr = np.zeros((len(sequence), num_entries), dtype=np.int32) + + for aa_index, aa_type in enumerate(sequence): + if map_unknown_to_x: + if aa_type.isalpha() and aa_type.isupper(): + aa_id = mapping.get(aa_type, mapping["X"]) + else: + raise ValueError(f"Invalid character in the sequence: {aa_type}") + else: + aa_id = mapping[aa_type] + one_hot_arr[aa_index, aa_id] = 1 + + return one_hot_arr + + +restype_1to3 = { + "A": "ALA", + "R": "ARG", + "N": "ASN", + "D": "ASP", + "C": "CYS", + "Q": "GLN", + "E": "GLU", + "G": "GLY", + "H": "HIS", + "I": "ILE", + "L": "LEU", + "K": "LYS", + "M": "MET", + "F": "PHE", + "P": "PRO", + "S": "SER", + "T": "THR", + "W": "TRP", + "Y": "TYR", + "V": "VAL", + "X": "UNK", +} + + +# NB: restype_3to1 differs from Bio.PDB.protein_letters_3to1 by being a simple +# 1-to-1 mapping of 3 letter names to one letter names. The latter contains +# many more, and less common, three letter names as keys and maps many of these +# to the same one letter name (including 'X' and 'U' which we don't use here). +restype_3to1 = {v: k for k, v in restype_1to3.items()} + +# Define a restype name for all unknown residues. +unk_restype = "UNK" + +resnames = [restype_1to3[r] for r in restypes] + [unk_restype] +resname_to_idx = {resname: i for i, resname in enumerate(resnames)} + +hydrophobic_resnames = {"VAL", "ILE", "LEU", "PHE", "MET", "TRP"} + +# The mapping here uses hhblits convention, so that B is mapped to D, J and O +# are mapped to X, U is mapped to C, and Z is mapped to E. Other than that the +# remaining 20 amino acids are kept in alphabetical order. +# There are 2 non-amino acid codes, X (representing any amino acid) and +# "-" representing a missing amino acid in an alignment. The id for these +# codes is put at the end (20 and 21) so that they can easily be ignored if +# desired. +HHBLITS_AA_TO_ID = { + "A": 0, + "B": 2, + "C": 1, + "D": 2, + "E": 3, + "F": 4, + "G": 5, + "H": 6, + "I": 7, + "J": 20, + "K": 8, + "L": 9, + "M": 10, + "N": 11, + "O": 20, + "P": 12, + "Q": 13, + "R": 14, + "S": 15, + "T": 16, + "U": 1, + "V": 17, + "W": 18, + "X": 20, + "Y": 19, + "Z": 3, + "-": 21, +} + +# Partial inversion of HHBLITS_AA_TO_ID. +ID_TO_HHBLITS_AA = { + 0: "A", + 1: "C", # Also U. + 2: "D", # Also B. + 3: "E", # Also Z. + 4: "F", + 5: "G", + 6: "H", + 7: "I", + 8: "K", + 9: "L", + 10: "M", + 11: "N", + 12: "P", + 13: "Q", + 14: "R", + 15: "S", + 16: "T", + 17: "V", + 18: "W", + 19: "Y", + 20: "X", # Includes J and O. + 21: "-", +} + +restypes_with_x_and_gap = restypes + ["X", "-"] +MAP_HHBLITS_AATYPE_TO_OUR_AATYPE = tuple( + restypes_with_x_and_gap.index(ID_TO_HHBLITS_AA[i]) + for i in range(len(restypes_with_x_and_gap)) +) + + +def _make_standard_atom_mask() -> np.ndarray: + """Returns [num_res_types, num_atom_types] mask array.""" + # +1 to account for unknown (all 0s). + mask = np.zeros([restype_num + 1, atom_type_num], dtype=np.int32) + for restype, restype_letter in enumerate(restypes): + restype_name = restype_1to3[restype_letter] + atom_names = residue_atoms[restype_name] + for atom_name in atom_names: + atom_type = atom_order[atom_name] + mask[restype, atom_type] = 1 + return mask + + +STANDARD_ATOM_MASK = _make_standard_atom_mask() + + +# A one hot representation for the first and second atoms defining the axis +# of rotation for each chi-angle in each residue. +def chi_angle_atom(atom_index: int) -> np.ndarray: + """Define chi-angle rigid groups via one-hot representations.""" + chi_angles_index = {} + one_hots = [] + + for k, v in chi_angles_atoms.items(): + indices = [atom_types.index(s[atom_index]) for s in v] + indices.extend([-1] * (4 - len(indices))) + chi_angles_index[k] = indices + + for r in restypes: + res3 = restype_1to3[r] + one_hot = np.eye(atom_type_num)[chi_angles_index[res3]] + one_hots.append(one_hot) + + one_hots.append(np.zeros([4, atom_type_num])) # Add zeros for residue `X`. + one_hot = np.stack(one_hots, axis=0) + one_hot = np.transpose(one_hot, [0, 2, 1]) + + return one_hot + + +chi_atom_1_one_hot = chi_angle_atom(1) +chi_atom_2_one_hot = chi_angle_atom(2) + +# An array like chi_angles_atoms but using indices rather than names. +chi_angles_atom_indices = [chi_angles_atoms[restype_1to3[r]] for r in restypes] +# chi_angles_atom_indices = tree.map_structure( +# lambda atom_name: atom_order[atom_name], chi_angles_atom_indices +# ) +chi_angles_atom_indices = np.array( + [ + chi_atoms + ([[0, 0, 0, 0]] * (4 - len(chi_atoms))) + for chi_atoms in chi_angles_atom_indices + ] +) + +# Mapping from (res_name, atom_name) pairs to the atom's chi group index +# and atom index within that group. +chi_groups_for_atom = collections.defaultdict(list) +for res_name, chi_angle_atoms_for_res in chi_angles_atoms.items(): + for chi_group_i, chi_group in enumerate(chi_angle_atoms_for_res): + for atom_i, atom in enumerate(chi_group): + chi_groups_for_atom[(res_name, atom)].append((chi_group_i, atom_i)) +chi_groups_for_atom = dict(chi_groups_for_atom) + + +def _make_rigid_transformation_4x4(ex, ey, translation): + """Create a rigid 4x4 transformation matrix from two axes and transl.""" + # Normalize ex. + ex_normalized = ex / np.linalg.norm(ex) + + # make ey perpendicular to ex + ey_normalized = ey - np.dot(ey, ex_normalized) * ex_normalized + ey_normalized /= np.linalg.norm(ey_normalized) + + # compute ez as cross product + eznorm = np.cross(ex_normalized, ey_normalized) + m = np.stack([ex_normalized, ey_normalized, eznorm, translation]).transpose() + m = np.concatenate([m, [[0.0, 0.0, 0.0, 1.0]]], axis=0) + return m + + +# create an array with (restype, atomtype) --> rigid_group_idx +# and an array with (restype, atomtype, coord) for the atom positions +# and compute affine transformation matrices (4,4) from one rigid group to the +# previous group +restype_atom37_to_rigid_group = np.zeros([21, 37], dtype=int) +restype_atom37_mask = np.zeros([21, 37], dtype=np.float32) +restype_atom37_rigid_group_positions = np.zeros([21, 37, 3], dtype=np.float32) +restype_atom14_to_rigid_group = np.zeros([21, 14], dtype=int) +restype_atom14_mask = np.zeros([21, 14], dtype=np.float32) +restype_atom14_rigid_group_positions = np.zeros([21, 14, 3], dtype=np.float32) +restype_rigid_group_default_frame = np.zeros([21, 8, 4, 4], dtype=np.float32) + + +def _make_rigid_group_constants(): + """Fill the arrays above.""" + for restype, restype_letter in enumerate(restypes_with_x): + resname = restype_1to3[restype_letter] + for atomname, group_idx, atom_position in rigid_group_atom_positions[resname]: + atomtype = atom_order[atomname] + restype_atom37_to_rigid_group[restype, atomtype] = group_idx + restype_atom37_mask[restype, atomtype] = 1 + restype_atom37_rigid_group_positions[restype, atomtype, :] = atom_position + + atom14idx = restype_name_to_atom14_names[resname].index(atomname) + restype_atom14_to_rigid_group[restype, atom14idx] = group_idx + restype_atom14_mask[restype, atom14idx] = 1 + restype_atom14_rigid_group_positions[restype, atom14idx, :] = atom_position + + for restype, restype_letter in enumerate(restypes_with_x): + resname = restype_1to3[restype_letter] + atom_positions = { + name: np.array(pos) for name, _, pos in rigid_group_atom_positions[resname] + } + + # backbone to backbone is the identity transform + restype_rigid_group_default_frame[restype, 0, :, :] = np.eye(4) + + # pre-omega-frame to backbone (currently dummy identity matrix) + restype_rigid_group_default_frame[restype, 1, :, :] = np.eye(4) + + # phi-frame to backbone + mat = _make_rigid_transformation_4x4( + ex=atom_positions["N"] - atom_positions["CA"], + ey=np.array([1.0, 0.0, 0.0]), + translation=atom_positions["N"], + ) + restype_rigid_group_default_frame[restype, 2, :, :] = mat + + # psi-frame to backbone + mat = _make_rigid_transformation_4x4( + ex=atom_positions["C"] - atom_positions["CA"], + ey=atom_positions["CA"] - atom_positions["N"], + translation=atom_positions["C"], + ) + restype_rigid_group_default_frame[restype, 3, :, :] = mat + + # chi1-frame to backbone + if chi_angles_mask[restype][0]: + base_atom_names = chi_angles_atoms[resname][0] + base_atom_positions = [atom_positions[name] for name in base_atom_names] + mat = _make_rigid_transformation_4x4( + ex=base_atom_positions[2] - base_atom_positions[1], + ey=base_atom_positions[0] - base_atom_positions[1], + translation=base_atom_positions[2], + ) + restype_rigid_group_default_frame[restype, 4, :, :] = mat + + # chi2-frame to chi1-frame + # chi3-frame to chi2-frame + # chi4-frame to chi3-frame + # luckily all rotation axes for the next frame start at (0,0,0) of the + # previous frame + for chi_idx in range(1, 4): + if chi_angles_mask[restype][chi_idx]: + axis_end_atom_name = chi_angles_atoms[resname][chi_idx][2] + axis_end_atom_position = atom_positions[axis_end_atom_name] + mat = _make_rigid_transformation_4x4( + ex=axis_end_atom_position, + ey=np.array([-1.0, 0.0, 0.0]), + translation=axis_end_atom_position, + ) + restype_rigid_group_default_frame[restype, 4 + chi_idx, :, :] = mat + + +_make_rigid_group_constants() + + +def make_atom14_dists_bounds(overlap_tolerance=1.5, bond_length_tolerance_factor=15.0): + """compute upper and lower bounds for bonds to assess violations.""" + restype_atom14_bond_lower_bound = np.zeros([21, 14, 14], np.float32) + restype_atom14_bond_upper_bound = np.zeros([21, 14, 14], np.float32) + restype_atom14_bond_stddev = np.zeros([21, 14, 14], np.float32) + residue_bonds, residue_virtual_bonds, _ = load_stereo_chemical_props() + for restype, restype_letter in enumerate(restypes): + resname = restype_1to3[restype_letter] + atom_list = restype_name_to_atom14_names[resname] + + # create lower and upper bounds for clashes + for atom1_idx, atom1_name in enumerate(atom_list): + if not atom1_name: + continue + atom1_radius = van_der_waals_radius[atom1_name[0]] + for atom2_idx, atom2_name in enumerate(atom_list): + if (not atom2_name) or atom1_idx == atom2_idx: + continue + atom2_radius = van_der_waals_radius[atom2_name[0]] + lower = atom1_radius + atom2_radius - overlap_tolerance + upper = 1e10 + restype_atom14_bond_lower_bound[restype, atom1_idx, atom2_idx] = lower + restype_atom14_bond_lower_bound[restype, atom2_idx, atom1_idx] = lower + restype_atom14_bond_upper_bound[restype, atom1_idx, atom2_idx] = upper + restype_atom14_bond_upper_bound[restype, atom2_idx, atom1_idx] = upper + + # overwrite lower and upper bounds for bonds and angles + for b in residue_bonds[resname] + residue_virtual_bonds[resname]: + atom1_idx = atom_list.index(b.atom1_name) + atom2_idx = atom_list.index(b.atom2_name) + lower = b.length - bond_length_tolerance_factor * b.stddev + upper = b.length + bond_length_tolerance_factor * b.stddev + restype_atom14_bond_lower_bound[restype, atom1_idx, atom2_idx] = lower + restype_atom14_bond_lower_bound[restype, atom2_idx, atom1_idx] = lower + restype_atom14_bond_upper_bound[restype, atom1_idx, atom2_idx] = upper + restype_atom14_bond_upper_bound[restype, atom2_idx, atom1_idx] = upper + restype_atom14_bond_stddev[restype, atom1_idx, atom2_idx] = b.stddev + restype_atom14_bond_stddev[restype, atom2_idx, atom1_idx] = b.stddev + return { + "lower_bound": restype_atom14_bond_lower_bound, # shape (21,14,14) + "upper_bound": restype_atom14_bond_upper_bound, # shape (21,14,14) + "stddev": restype_atom14_bond_stddev, # shape (21,14,14) + } + + +restype_atom14_ambiguous_atoms = np.zeros((21, 14), dtype=np.float32) +restype_atom14_ambiguous_atoms_swap_idx = np.tile(np.arange(14, dtype=int), (21, 1)) + + +def _make_atom14_ambiguity_feats(): + for res, pairs in residue_atom_renaming_swaps.items(): + res_idx = restype_order[restype_3to1[res]] + for atom1, atom2 in pairs.items(): + atom1_idx = restype_name_to_atom14_names[res].index(atom1) + atom2_idx = restype_name_to_atom14_names[res].index(atom2) + restype_atom14_ambiguous_atoms[res_idx, atom1_idx] = 1 + restype_atom14_ambiguous_atoms[res_idx, atom2_idx] = 1 + restype_atom14_ambiguous_atoms_swap_idx[res_idx, atom1_idx] = atom2_idx + restype_atom14_ambiguous_atoms_swap_idx[res_idx, atom2_idx] = atom1_idx + + +_make_atom14_ambiguity_feats() + + +def aatype_to_str_sequence(aatype): + return "".join([restypes_with_x[aatype[i]] for i in range(len(aatype))]) + + +# NOTE(thayes): These are computed based on the average CA->C and CA->N norm from rigid_group_atom_positions +CA_TO_N_NORM = 1.4591 +CA_TO_C_NORM = 1.5252 + + +def _make_restype_atom37_to_atom14(): + """Map from atom37 to atom14 per residue type.""" + restype_atom37_to_atom14 = [] # mapping (restype, atom37) --> atom14 + for rt in restypes: + atom_names = restype_name_to_atom14_names[restype_1to3[rt]] + atom_name_to_idx14 = {name: i for i, name in enumerate(atom_names)} + restype_atom37_to_atom14.append( + [ + (atom_name_to_idx14[name] if name in atom_name_to_idx14 else 0) + for name in atom_types + ] + ) + + restype_atom37_to_atom14.append([0] * 37) + restype_atom37_to_atom14 = np.array(restype_atom37_to_atom14, dtype=np.int32) + return restype_atom37_to_atom14 + + +def _make_restype_atom14_to_atom37(): + """Map from atom14 to atom37 per residue type.""" + restype_atom14_to_atom37 = [] # mapping (restype, atom14) --> atom37 + for rt in restypes: + atom_names = restype_name_to_atom14_names[restype_1to3[rt]] + restype_atom14_to_atom37.append( + [(atom_order[name] if name else 0) for name in atom_names] + ) + # Add dummy mapping for restype 'UNK' + restype_atom14_to_atom37.append([0] * 14) + restype_atom14_to_atom37 = np.array(restype_atom14_to_atom37, dtype=np.int32) + return restype_atom14_to_atom37 + + +RESTYPE_ATOM14_TO_ATOM37 = _make_restype_atom14_to_atom37() +RESTYPE_ATOM37_TO_ATOM14 = _make_restype_atom37_to_atom14() +CHAIN_BREAK_TOKEN = "|" diff --git a/esm/utils/sampling.py b/esm/utils/sampling.py index 68c5c868..fdf8658d 100644 --- a/esm/utils/sampling.py +++ b/esm/utils/sampling.py @@ -5,18 +5,9 @@ import torch import torch.nn.functional as F -from esm.sdk.api import ( - ESMProteinTensor, - SamplingConfig, - SamplingTrackConfig, -) -from esm.tokenization import ( - TokenizerCollectionProtocol, - get_invalid_tokenizer_ids, -) -from esm.tokenization.function_tokenizer import ( - InterProQuantizedTokenizer, -) +from esm.sdk.api import ESMProteinTensor, SamplingConfig, SamplingTrackConfig +from esm.tokenization import TokenizerCollectionProtocol, get_invalid_tokenizer_ids +from esm.tokenization.function_tokenizer import InterProQuantizedTokenizer from esm.utils.constants.esm3 import ( MAX_RESIDUE_ANNOTATIONS, SASA_DISCRETIZATION_BOUNDARIES, diff --git a/esm/utils/structure/affine3d.py b/esm/utils/structure/affine3d.py index 382abcd5..e2d9b27e 100644 --- a/esm/utils/structure/affine3d.py +++ b/esm/utils/structure/affine3d.py @@ -1,16 +1,17 @@ from __future__ import annotations import typing as T +from abc import ABC from dataclasses import dataclass import torch +from torch.nn import functional as F from typing_extensions import Self from esm.utils.misc import fp32_autocast_context -@T.runtime_checkable -class Rotation(T.Protocol): +class Rotation(ABC): @classmethod def identity(cls, shape: tuple[int, ...], **tensor_kwargs) -> Self: ... @@ -34,6 +35,8 @@ def shape(self) -> torch.Size: def as_matrix(self) -> RotationMatrix: ... + def as_quat(self, normalize: bool = False) -> RotationQuat: ... + def compose(self, other: Self) -> Self: # To be safe, we force users to explicitly convert between rotation types. ... @@ -87,7 +90,8 @@ def __init__(self, rots: torch.Tensor): assert rots.shape[-1] == 3 assert rots.shape[-2] == 3 # Force full precision - self._rots = rots.to(torch.float32) + rots = rots.to(torch.float32) + self._rots = rots @classmethod def identity(cls, shape, **tensor_kwargs): @@ -98,9 +102,7 @@ def identity(cls, shape, **tensor_kwargs): @classmethod def random(cls, shape, **tensor_kwargs): - v1 = torch.randn((*shape, 3), **tensor_kwargs) - v2 = torch.randn((*shape, 3), **tensor_kwargs) - return cls(_graham_schmidt(v1, v2)) + return RotationQuat.random(shape, **tensor_kwargs).as_matrix() def __getitem__(self, idx: T.Any) -> RotationMatrix: indices = (idx,) if isinstance(idx, int) or idx is None else tuple(idx) @@ -113,6 +115,49 @@ def shape(self) -> torch.Size: def as_matrix(self) -> RotationMatrix: return self + def as_quat(self, normalize: bool = False) -> RotationQuat: + m00, m01, m02, m10, m11, m12, m20, m21, m22 = torch.unbind( + self._rots.flatten(-2), dim=-1 + ) + q_abs = _sqrt_subgradient( + torch.stack( + [ + 1.0 + m00 + m11 + m22, + 1.0 + m00 - m11 - m22, + 1.0 - m00 + m11 - m22, + 1.0 - m00 - m11 + m22, + ], + dim=-1, + ) + ) + # we produce the desired quaternion multiplied by each of r, i, j, k + quat_by_rijk = torch.stack( + [ + x + for lst in [ + [q_abs[..., 0] ** 2, m21 - m12, m02 - m20, m10 - m01], + [m21 - m12, q_abs[..., 1] ** 2, m10 + m01, m02 + m20], + [m02 - m20, m10 + m01, q_abs[..., 2] ** 2, m12 + m21], + [m10 - m01, m20 + m02, m21 + m12, q_abs[..., 3] ** 2], + ] + for x in lst + ], + dim=-1, + ).unflatten(-1, (4, 4)) + + # We floor here at 0.1 but the exact level is not important; if q_abs is small, + # the candidate won't be picked. + flr = torch.tensor(0.1).to(dtype=q_abs.dtype, device=q_abs.device) + quat_candidates = quat_by_rijk / (2.0 * q_abs[..., None].max(flr)) + + # if not for numerical problems, quat_candidates[i] should be same (up to a sign), + # forall i; we pick the best-conditioned one (with the largest denominator) + # We manually implement one_hot so torch.compile works + one_hot = torch.zeros_like(q_abs, dtype=torch.bool) + one_hot.scatter_(-1, q_abs.argmax(dim=-1, keepdim=True), True) + quat = quat_candidates[one_hot, :].reshape(q_abs.shape) + return RotationQuat(quat) + def compose(self, other: RotationMatrix) -> RotationMatrix: with fp32_autocast_context(self._rots.device.type): return RotationMatrix(self._rots @ other._rots) @@ -147,6 +192,81 @@ def from_graham_schmidt( return RotationMatrix(_graham_schmidt(x_axis, xy_plane, eps)) +class RotationQuat(Rotation): + def __init__(self, quats: torch.Tensor, normalized=False): + assert quats.shape[-1] == 4 + self._normalized = normalized + # Force float32 as well + if normalized: + self._quats = F.normalize(quats.to(torch.float32), dim=-1) + self._quats = self._quats.where(self._quats[..., :1] >= 0, -self._quats) + else: + self._quats = quats.to(torch.float32) + + @classmethod + def identity(cls, shape, **tensor_kwargs): + q = torch.ones((*shape, 4), **tensor_kwargs) + mult = torch.tensor([1, 0, 0, 0], device=q.device) + return RotationQuat(q * mult) + + @classmethod + def random(cls, shape, **tensor_kwargs): + quat = torch.randn((*shape, 4), **tensor_kwargs) + return RotationQuat(quat, normalized=True) + + def __getitem__(self, idx: T.Any) -> RotationQuat: + indices = (idx,) if isinstance(idx, int) or idx is None else tuple(idx) + return RotationQuat(self._quats[indices + (slice(None),)]) + + @property + def shape(self) -> torch.Size: + return self._quats.shape[:-1] + + def compose(self, other: RotationQuat) -> RotationQuat: + with fp32_autocast_context(self._quats.device.type): + return RotationQuat(_quat_mult(self._quats, other._quats)) + + def convert_compose(self, other: Rotation): + return self.compose(other.as_quat()) + + def as_matrix(self) -> RotationMatrix: + q = self.normalized().tensor + r, i, j, k = torch.unbind(q, -1) + two_s = 2.0 / torch.linalg.norm(q, dim=-1) + + o = torch.stack( + ( + 1 - two_s * (j * j + k * k), + two_s * (i * j - k * r), + two_s * (i * k + j * r), + two_s * (i * j + k * r), + 1 - two_s * (i * i + k * k), + two_s * (j * k - i * r), + two_s * (i * k - j * r), + two_s * (j * k + i * r), + 1 - two_s * (i * i + j * j), + ), + -1, + ) + return RotationMatrix(o.reshape(q.shape[:-1] + (3, 3))) + + def as_quat(self, normalize: bool = False) -> RotationQuat: + return self + + def apply(self, p: torch.Tensor) -> torch.Tensor: + return _quat_rotation(self.normalized()._quats, p) + + def invert(self) -> RotationQuat: + return RotationQuat(_quat_invert(self._quats)) + + @property + def tensor(self) -> torch.Tensor: + return self._quats + + def normalized(self) -> RotationQuat: + return self if self._normalized else RotationQuat(self._quats, normalized=True) + + @dataclass(frozen=True) class Affine3D: trans: torch.Tensor @@ -222,6 +342,9 @@ def tensor_apply(self, func) -> "Affine3D": def as_matrix(self): return Affine3D(trans=self.trans, rot=self.rot.as_matrix()) + def as_quat(self, normalize: bool = False): + return Affine3D(trans=self.trans, rot=self.rot.as_quat(normalize)) + def compose(self, other: "Affine3D", autoconvert: bool = False): rot = self.rot new_rot = (rot.convert_compose if autoconvert else rot.compose)(other.rot) @@ -271,6 +394,13 @@ def from_tensor(t: torch.Tensor) -> "Affine3D": # Assume tensor 4x4 for backward compat with alphafold trans = t[..., :3, 3] rot = RotationMatrix(t[..., :3, :3]) + case 6: + # Assume quaternion representation with real part = 1 + trans = t[..., -3:] + rot = RotationQuat(F.pad(t[..., :3], (1, 0), value=1)) + case 7: + trans = t[..., -3:] + rot = RotationQuat(t[..., :4]) case 12: trans = t[..., -3:] rot = RotationMatrix(t[..., :-3].unflatten(-1, (3, 3))) @@ -305,6 +435,62 @@ def cat(affines: list["Affine3D"], dim: int = 0): return Affine3D.from_tensor(torch.cat([x.tensor for x in affines], dim=dim)) +def _quat_mult(a: torch.Tensor, b: torch.Tensor) -> torch.Tensor: + """ + Multiply two quaternions. + Usual torch rules for broadcasting apply. + + Args: + a: Quaternions as tensor of shape (..., 4), real part first. + b: Quaternions as tensor of shape (..., 4), real part first. + + Returns: + The product of a and b, a tensor of quaternions shape (..., 4). + """ + aw, ax, ay, az = torch.unbind(a, -1) + bw, bx, by, bz = torch.unbind(b, -1) + ow = aw * bw - ax * bx - ay * by - az * bz + ox = aw * bx + ax * bw + ay * bz - az * by + oy = aw * by - ax * bz + ay * bw + az * bx + oz = aw * bz + ax * by - ay * bx + az * bw + return torch.stack((ow, ox, oy, oz), -1) + + +def _quat_rotation(q: torch.Tensor, p: torch.Tensor) -> torch.Tensor: + """ + Rotates p by quaternion q. Usual torch rules for broadcasting apply. + + Args: + q: Quaternions as tensor of shape (..., 4), real part first. + p: Points as tensor of shape (..., 3) + + Returns: + The rotated version of p, of shape (..., 3) + """ + aw, ax, ay, az = torch.unbind(q, -1) + bx, by, bz = torch.unbind(p, -1) + # fmt: off + ow = - ax * bx - ay * by - az * bz + ox = aw * bx + ay * bz - az * by + oy = aw * by - ax * bz + az * bx + oz = aw * bz + ax * by - ay * bx + # fmt: on + q_mul_pts = torch.stack((ow, ox, oy, oz), -1) + return _quat_mult(q_mul_pts, _quat_invert(q))[..., 1:] + + +def _quat_invert(q: torch.Tensor): + return q * torch.tensor([1, -1, -1, -1], device=q.device) + + +def _sqrt_subgradient(x: torch.Tensor) -> torch.Tensor: + # Returns torch.sqrt(torch.max(0, x)) but with a zero subgradient where x is 0. + ret = torch.zeros_like(x) + positive_mask = x > 0 + ret[positive_mask] = torch.sqrt(x[positive_mask]) + return ret + + def _graham_schmidt(x_axis: torch.Tensor, xy_plane: torch.Tensor, eps: float = 1e-12): # A low eps here is necessary for good stability! with fp32_autocast_context(x_axis.device.type): diff --git a/esm/utils/structure/aligner.py b/esm/utils/structure/aligner.py index ec0a3ef1..f25d9987 100644 --- a/esm/utils/structure/aligner.py +++ b/esm/utils/structure/aligner.py @@ -6,17 +6,21 @@ import numpy as np import torch -from esm.utils.structure.protein_structure import ( - compute_affine_and_rmsd, -) +from esm.utils.structure.protein_structure import compute_affine_and_rmsd class Alignable(Protocol): - atom37_positions: np.ndarray - atom37_mask: np.ndarray # Trick to detect whether an object is a dataclass __dataclass_fields__: ClassVar[dict[str, Field[Any]]] + @property + def atom37_positions(self) -> np.ndarray: # type: ignore + pass + + @property + def atom37_mask(self) -> np.ndarray: # type: ignore + pass + def __len__(self) -> int: ... diff --git a/esm/utils/structure/atom_indexer.py b/esm/utils/structure/atom_indexer.py new file mode 100644 index 00000000..d62f05c9 --- /dev/null +++ b/esm/utils/structure/atom_indexer.py @@ -0,0 +1,15 @@ +import numpy as np + +from esm.utils.structure.protein_structure import index_by_atom_name + + +class AtomIndexer: + def __init__(self, structure, property: str, dim: int): + self.structure = structure + self.property = property + self.dim = dim + + def __getitem__(self, atom_names: str | list[str]) -> np.ndarray: + return index_by_atom_name( + getattr(self.structure, self.property), atom_names, self.dim + ) diff --git a/esm/utils/structure/metrics.py b/esm/utils/structure/metrics.py index dfe26ebc..d76ed766 100644 --- a/esm/utils/structure/metrics.py +++ b/esm/utils/structure/metrics.py @@ -1,19 +1,148 @@ +import numpy as np import torch +import torch.nn.functional as F from einops import rearrange +from torch import Tensor +from torch.amp import autocast # type: ignore from esm.utils import residue_constants -from esm.utils.misc import unbinpack +from esm.utils.misc import binpack, unbinpack from esm.utils.structure.protein_structure import ( compute_alignment_tensors, compute_gdt_ts_no_alignment, + compute_rmsd_no_alignment, ) +def contact_precision( + predictions: Tensor, + targets: Tensor, + src_lengths: Tensor | None = None, + minsep: int = 6, + maxsep: int | None = None, + override_length: int | None = None, # for casp +): + """Computes contact precisions. + + For protein contact prediction, precision is measured for the top (L/K) highest confidence predictions, + with L being the length of the protein sequence and K generally being equal to 1 or 5. + + K = 5 measures the predictions of the very highest confidence contacts, while K = 1 is a more general measure + over all relatively high confidence predictions. + + Since there are roughly ~L true contacts in a protein, this is a reasonable cutoff. + + + Args: + predictions (Tensor): Tensor of probabilities of size (B, L, L) + targets (Tensor): Tensor of true contacts of size (B, L, L) + src_lengths (Tensor, optional): Lengths of each sample in the batch, if using variable lengths. + If not provided, inferred from the size of the predictions. + minsep (int): Minimum separation distance to consider. We often want to measure contacts at a + certain range. Typical ranges are short [6, 12), medium [12, 24), and long [24, inf). + maxsep (int, optional): Used in conjunction with minsep to specify a contact range. If not provided uses + assumes no maximum range + override_length (int, optional): Used for casp evaluation where sometimes the "true" length is not + the same as the length of the input. Kept for posterity, we probably don't need this argument. + """ + if predictions.dim() == 2: + predictions = predictions.unsqueeze(0) + if targets.dim() == 2: + targets = targets.unsqueeze(0) + + # Check sizes + if predictions.size() != targets.size(): + raise ValueError( + f"Size mismatch. Received predictions of size {predictions.size()}, " + f"targets of size {targets.size()}" + ) + device = predictions.device + + batch_size, seqlen, _ = predictions.size() + + # Step 1) Construct a mask of size [B, L, L] to mask invalid contacts + seqlen_range = torch.arange(seqlen, device=device) + sep = seqlen_range.unsqueeze(0) - seqlen_range.unsqueeze(1) + sep = sep.unsqueeze(0) + # Mask contacts that are closer than minsep + valid_mask = sep >= minsep + # Mask contacts where target is negative (padding or unknown) + valid_mask = valid_mask & (targets >= 0) # negative targets are invalid + + # Mask contacts that are farther than maxsep, if provided + if maxsep is not None: + valid_mask &= sep < maxsep + + if src_lengths is not None: + # If the lengths of the individual sequences are provided, mask positions + # that are farther than the end of the sequence. + valid = seqlen_range.unsqueeze(0) < src_lengths.unsqueeze(1) + valid_mask &= valid.unsqueeze(1) & valid.unsqueeze(2) + else: + src_lengths = torch.full([batch_size], seqlen, device=device, dtype=torch.long) + + # Fill in the logit tensor with -inf for all invalid positions + predictions = predictions.masked_fill(~valid_mask, float("-inf")) + + # Step 2) Select the top half of the prediction (should be symmetric) + x_ind, y_ind = np.triu_indices(seqlen, minsep) + predictions_upper = predictions[:, x_ind, y_ind] + targets_upper = targets[:, x_ind, y_ind] + + # Step 3) Select the topk values in each batch where k = L (length of sequence) + topk = seqlen if override_length is None else max(seqlen, override_length) + # Indices are the indices into the predictions corresponding to the most confident predictions + indices = predictions_upper.argsort(dim=-1, descending=True)[:, :topk] + # topk_targets are the target values corresponding to the above indices + topk_targets = targets_upper[torch.arange(batch_size).unsqueeze(1), indices] + if topk_targets.size(1) < topk: + # If there aren't enough targets, pad to the output. + topk_targets = F.pad(topk_targets, [0, topk - topk_targets.size(1)]) + + # Step 4) Sum the accuracy at of the top-i predictions for i in 1, L + # topk_targets => 1/0 true vs. false contact, sorted by confidence of prediction + # cmumulative sum => Number of correct answers for the top-i predictions. + cumulative_dist = topk_targets.type_as(predictions).cumsum(-1) + + # Step 5) Find the gather indices. This should be P@(L / K) for varous values of K + # The values will differ for each batch. + gather_lengths = src_lengths.unsqueeze(1) + if override_length is not None: + gather_lengths = override_length * torch.ones_like( + gather_lengths, device=device + ) + + # This gets you (0.1 * L, 0.2 * L, 0.3 * L, etc.) + gather_indices = ( + (torch.arange(0.1, 1.1, 0.1, device=device).unsqueeze(0) * gather_lengths).type( + torch.long + ) + - 1 + ).clamp_min(0) + + # Step 6) Gather the results and divide by the number of guesses to get the precision. + binned_cumulative_dist = cumulative_dist.gather(1, gather_indices) + binned_precisions = binned_cumulative_dist / (gather_indices + 1).type_as( + binned_cumulative_dist + ) + + # Select specific P@L/k. pl5 is index 1 b/c that corresponds to L * 0.2 in + # gather_indices above + pl5 = binned_precisions[:, 1] + # pl2 = binned_precisions[:, 4] + pl = binned_precisions[:, 9] + # AUC is the integral wrt K of P@L/K for K in range(1, L) + auc = binned_precisions.mean(-1) + + return {"AUC": auc, "P@L": pl, "P@L5": pl5} + + def compute_lddt( all_atom_pred_pos: torch.Tensor, all_atom_positions: torch.Tensor, all_atom_mask: torch.Tensor, - cutoff: float = 15.0, + pairwise_all_atom_mask: torch.Tensor | None = None, + cutoff: float | torch.Tensor = 15.0, eps: float = 1e-10, per_residue: bool = True, sequence_id: torch.Tensor | None = None, @@ -29,7 +158,8 @@ def compute_lddt( all_atom_pred_pos (Tensor[float], [(Nstates x) B x (L * Natoms x) 3]): Tensor of predicted positions all_atom_positions (Tensor[float], [B x (L * Natoms x) 3]): Tensor of true positions all_atom_mask (Tensor[float], [B x (L * Natoms)]): Tensor of masks, indicating whether an atom exists. - cutoff (float): Max distance to score lddt over. + pairwise_all_atom_mask (Tensor[float], [B x (L * Natoms x L * Natoms)], optional): Tensor of masks, indicating whether a pair of atoms should be considered in the LDDT calculation. + cutoff (float): Max distance to score lddt over. This can either be a float, or a tensor of shape [B, L, L] to allow for per-residue cutoffs, e.g. if you want to use a different cutoff for nucleic acids. per_residue (bool): Whether to return per-residue or full-protein lddt. sequence_id (Tensor, optional): Sequence id tensor for binpacking. NOTE: only supported for lddt_ca calculations, not when Natoms is passed! @@ -40,7 +170,7 @@ def compute_lddt( else: Tensor[float], [(Nstates x) B] """ - n = all_atom_mask.shape[-2] + all_atom_mask = all_atom_mask[..., None] # add a dimension for broadcasting dmat_true = torch.sqrt( eps + torch.sum( @@ -57,22 +187,56 @@ def compute_lddt( dim=-1, ) ) - dists_to_score = ( - (dmat_true < cutoff) - * all_atom_mask - * rearrange(all_atom_mask, "... a b -> ... b a") - * (1.0 - torch.eye(n, device=all_atom_mask.device)) - ) + mask = all_atom_mask * rearrange(all_atom_mask, "... a b -> ... b a") + if pairwise_all_atom_mask is not None: + mask = mask * pairwise_all_atom_mask if sequence_id is not None: - # TODO(roshan): This will work for lddt_ca, but not for regular lddt + # TODO: This will work for lddt_ca, but not for regular lddt # Problem is that regular lddt has natoms * nres scores, so would need to repeat this mask by natoms # Leaving for now because it won't fail silently so should be ook. seqid_mask = sequence_id[..., None] == sequence_id[..., None, :] - dists_to_score = dists_to_score * seqid_mask.type_as(dists_to_score) + mask = mask * seqid_mask.type_as(mask) + + return compute_lddt_from_dmat( + dmat_pred, dmat_true, mask, cutoff=cutoff, eps=eps, per_residue=per_residue + ) - dist_l1 = torch.abs(dmat_true - dmat_pred) +def compute_lddt_from_dmat( + dmat_pred: torch.Tensor, + dmat_true: torch.Tensor, + pairwise_mask: torch.Tensor, + cutoff: float | torch.Tensor = 15.0, + eps: float = 1e-10, + per_residue: bool = True, +): + """ + Compute LDDT from pre-computed distance matrices. + This is useful when you want to compute LDDT with multiple different masks or cutoffs, e.g. for different molecule types (protein, nucleic acid, etc.). + + Args: + dmat_pred (Tensor[float], [B x L x L]): Predicted distance matrix + dmat_true (Tensor[float], [B x L x L]): True distance matrix + pairwise_mask (Tensor[float], [B x L x L]): Pairwise mask indicating which pairs of atoms to consider + cutoff (float): Max distance to score lddt over. This can either be a float, or a tensor of shape [B, L, L] to allow for per-residue cutoffs, e.g. if you want to use a different cutoff for nucleic acids. + per_residue (bool): Whether to return per-residue or full-protein lddt. + + Returns: + LDDT Tensor: + if per_residue: + Tensor[float], [B x L] + else: + Tensor[float], [B] + """ + n = dmat_true.size(-1) + dists_to_score = ( + (dmat_true < cutoff) + * pairwise_mask + * (1.0 - torch.eye(n, device=dmat_true.device)) + ) + + dist_l1 = torch.abs(dmat_true - dmat_pred) score = ( (dist_l1 < 0.5).type(dist_l1.dtype) + (dist_l1 < 1.0).type(dist_l1.dtype) @@ -84,7 +248,6 @@ def compute_lddt( dims = (-1,) if per_residue else (-2, -1) norm = 1.0 / (eps + torch.sum(dists_to_score, dim=dims)) score = norm * (eps + torch.sum(dists_to_score * score, dim=dims)) - return score @@ -114,6 +277,56 @@ def compute_lddt_ca( ) +# NOTE(roshan): no_grad required for stack_variable_length_tensors apparently... let's revisit if we want to backprop +@torch.no_grad() +@autocast("cuda", enabled=False) +def compute_rmsd( + mobile: torch.Tensor, + target: torch.Tensor, + atom_exists_mask: torch.Tensor | None = None, + sequence_id: torch.Tensor | None = None, + reduction: str = "batch", +): + """ + Compute RMSD between two batches of structures with support for masking invalid atoms using PyTorch. + + Args: + - mobile (torch.Tensor): Batch of coordinates of structure to be superimposed in shape (B, N, 3) + - target (torch.Tensor): Batch of coordinates of structure that is fixed in shape (B, N, 3) + - atom_exists_mask (torch.Tensor, optional): Mask for Whether an atom exists of shape (B, N) + - sequence_id (torch.Tensor, optional): Sequence id tensor for binpacking. + - reduction (str): One of "batch", "per_sample", "per_residue". + + Returns: + If reduction == "batch": + (torch.Tensor): 0-dim, Average Root Mean Square Deviation between the structures for each batch + If reduction == "per_sample": + (torch.Tensor): (B,)-dim, Root Mean Square Deviation between the structures for each batch + If reduction == "per_residue": + (torch.Tensor): (B, N)-dim, Root Mean Square Deviation between the structures for residue in the batch + """ + + (centered_mobile, _, centered_target, _, rotation_matrix, num_valid_atoms) = ( + compute_alignment_tensors( + mobile=mobile, + target=target, + atom_exists_mask=atom_exists_mask, + sequence_id=sequence_id, + ) + ) + + # Apply transformation to centered structure + rotated_mobile = torch.matmul(centered_mobile, rotation_matrix) + + # Compute rmsd for centered structures + rmsd = compute_rmsd_no_alignment( + rotated_mobile, centered_target, num_valid_atoms, reduction=reduction + ) + if reduction == "per_residue" and sequence_id is not None: + rmsd = binpack(rmsd, sequence_id, pad_value=0) + return rmsd + + def compute_gdt_ts( mobile: torch.Tensor, target: torch.Tensor, diff --git a/esm/utils/structure/mmcif_parsing.py b/esm/utils/structure/mmcif_parsing.py new file mode 100644 index 00000000..3509ffb1 --- /dev/null +++ b/esm/utils/structure/mmcif_parsing.py @@ -0,0 +1,469 @@ +from __future__ import annotations + +import functools +import io +import os +from dataclasses import dataclass +from datetime import datetime +from typing import Union + +import biotite.structure as bs +import biotite.structure.io.pdbx as pdbx + +from esm.utils import residue_constants + +# Define PathOrBuffer for the opensource version +PathOrBuffer = Union[str, os.PathLike, io.StringIO] + + +class NoProteinError(Exception): + pass + + +@dataclass +class Residue: + residue_number: int | None = None + insertion_code: str = "" + hetflag: bool = False + + +@dataclass +class MmcifHeader: + release_date: datetime | None = None + resolution: float | None = None + structure_method: str = "UNKNOWN" + + +class MmcifWrapper: + def __init__(self, id: str | None = None): + self.id: str = id or "" + self.raw: pdbx.CIFFile | None = None + self.structure: bs.AtomArray + self.header: MmcifHeader = MmcifHeader() + self.entities: dict[int, list[str]] = {} + self.chain_to_seqres: dict[str, str] = {} + self.seqres_to_structure: dict[str, dict[int, Residue]] = {} + + @classmethod + def read(cls, path: PathOrBuffer, id: str | None = None) -> MmcifWrapper: + obj = cls(id=id) + obj._load(path) + return obj + + def _load(self, path: PathOrBuffer, fileid: str | None = None): + """Load mmCIF data from file.""" + self.raw = pdbx.CIFFile.read(path) + + self._parse_structure() + self._parse_header() + self._parse_entities() + self._parse_sequences() + + def _parse_structure(self): + """Parse the atomic structure from mmCIF.""" + try: + structure = pdbx.get_structure(self.raw, model=1) + if structure is None or not isinstance(structure, bs.AtomArray): + raise NoProteinError("No structure found in mmCIF file") + if len(structure) == 0: + raise NoProteinError("Empty structure in mmCIF file") + self.structure = structure + except Exception as e: + raise ValueError(f"Failed to parse structure: {e}") + + def _parse_header(self): + """Parse header information from mmCIF.""" + if not self.raw: + return + + try: + # Get the first (and usually only) block + block = self.raw.block + + # Parse release date + if "pdbx_database_status" in block: + status_cat = block["pdbx_database_status"] + if "recvd_initial_deposition_date" in status_cat: + date_str = status_cat["recvd_initial_deposition_date"].as_item() + if date_str and date_str != "?": + try: + self.header.release_date = datetime.strptime( + date_str, "%Y-%m-%d" + ) + except ValueError: + pass + + # Parse resolution + if "refine" in block: + refine_cat = block["refine"] + if "ls_d_res_high" in refine_cat: + res_str = refine_cat["ls_d_res_high"].as_item() + if res_str and res_str != "?": + try: + self.header.resolution = float(res_str) + except ValueError: + pass + + # Parse structure method + if "exptl" in block: + exptl_cat = block["exptl"] + if "method" in exptl_cat: + method = exptl_cat["method"].as_item() + if method and method != "?": + self.header.structure_method = method.upper() + + except Exception: + # If parsing fails, keep default values + pass + + def _parse_entities(self): + """Parse entity information and map to chains.""" + if not self.raw: + return + + try: + block = self.raw.block + + # Parse entity information + if "entity" in block: + entity_cat = block["entity"] + entity_ids = entity_cat["id"].as_array(str) + entity_types = entity_cat["type"].as_array(str) + + # Initialize entities dict with all entities (not just polymers) + for i, (entity_id, entity_type) in enumerate( + zip(entity_ids, entity_types) + ): + self.entities[int(entity_id)] = [] + + # Map polymer chains to entities using entity_poly + if "entity_poly" in block: + poly_cat = block["entity_poly"] + entity_ids = poly_cat["entity_id"].as_array(str) + chain_lists = poly_cat["pdbx_strand_id"].as_array(str) + + for entity_id, chain_list in zip(entity_ids, chain_lists): + entity_id = int(entity_id) + # Chain list is comma-separated + chains = [c.strip() for c in chain_list.split(",") if c.strip()] + if entity_id in self.entities: + self.entities[entity_id] = chains + + # Map non-polymer chains using struct_asym for entities not covered by entity_poly + if "struct_asym" in block: + asym_cat = block["struct_asym"] + asym_ids = asym_cat["id"].as_array(str) + entity_ids = asym_cat["entity_id"].as_array(str) + + for asym_id, entity_id in zip(asym_ids, entity_ids): + entity_id = int(entity_id) + # Only add if entity exists but has no chains yet (non-polymer entities) + if entity_id in self.entities and not self.entities[entity_id]: + self.entities[entity_id].append(asym_id) + + except Exception: + # If parsing fails, try to infer from structure + if ( + self.structure + and hasattr(self.structure, "chain_id") + and self.structure.chain_id is not None + and hasattr(self.structure.chain_id, "__iter__") + ): + chain_ids = list(set(self.structure.chain_id)) + self.entities = {1: chain_ids} + + def _parse_sequences(self): + """Parse sequence information from mmCIF.""" + if not self.raw: + return + + block = self.raw.block + + # Parse polymer sequences + if "entity_poly" in block: + poly_cat = block["entity_poly"] + entity_ids = poly_cat["entity_id"].as_array(str) + sequences = poly_cat["pdbx_seq_one_letter_code_can"].as_array(str) + chain_lists = poly_cat["pdbx_strand_id"].as_array(str) + + for entity_id, sequence, chain_list in zip( + entity_ids, sequences, chain_lists + ): + # Clean up sequence (remove whitespace and newlines) + clean_seq = "".join(sequence.split()) + chains = [c.strip() for c in chain_list.split(",") if c.strip()] + + for chain_id in chains: + self.chain_to_seqres[chain_id] = clean_seq + + # Parse sequence to structure mapping + if "pdbx_poly_seq_scheme" in block: + seq_cat = block["pdbx_poly_seq_scheme"] + asym_ids = seq_cat["asym_id"].as_array(str) # Internal chain IDs + seq_positions = seq_cat["seq_id"].as_array(str) + auth_seq_nums = seq_cat["auth_seq_num"].as_array(str) + ins_codes = ( + seq_cat["pdb_ins_code"].as_array(str) + if "pdb_ins_code" in seq_cat + else [""] * len(asym_ids) + ) + hetflags = ( + seq_cat["hetflag"].as_array(str) + if "hetflag" in seq_cat + else ["N"] * len(asym_ids) + ) + + # Get author chain IDs if available + auth_chain_ids = ( + seq_cat["pdb_strand_id"].as_array(str) + if "pdb_strand_id" in seq_cat + else asym_ids # Fallback to internal IDs + ) + + # Build mapping from internal chain ID to author chain ID + asym_to_auth_mapping = {} + for asym_id, auth_id in zip(asym_ids, auth_chain_ids): + asym_to_auth_mapping[asym_id] = auth_id + + # Group by internal chain ID first, then map to author chain ID + chain_data = {} + for asym_id, seq_pos, auth_seq, ins_code, hetflag in zip( + asym_ids, seq_positions, auth_seq_nums, ins_codes, hetflags + ): + if asym_id not in chain_data: + chain_data[asym_id] = {} + + try: + seq_index = int(seq_pos) - 1 # Convert to 0-based indexing + res_num = int(auth_seq) if auth_seq != "?" else None + except ValueError: + continue + + if res_num is not None: + # Convert mmCIF "." and "?" to empty string + clean_ins_code = "" if ins_code in [".", "?"] else ins_code + else: + clean_ins_code = "" + res_num = None + + is_het = hetflag.upper() == "Y" # type: ignore + chain_data[asym_id][seq_index] = Residue( + residue_number=res_num, + insertion_code=clean_ins_code, # type: ignore + hetflag=is_het, + ) + + # Handle cases where multiple residues have the same auth_seq_num + # by adjusting residue numbers to be unique within each chain + for asym_id, residue_data in chain_data.items(): + # Check if there are duplicate residue numbers in this chain + positions_with_same_num = {} + for seq_idx, res_at_pos in residue_data.items(): + if res_at_pos.residue_number is not None: + res_num = res_at_pos.residue_number + if res_num not in positions_with_same_num: + positions_with_same_num[res_num] = [] + positions_with_same_num[res_num].append(seq_idx) + + # Fix duplicate residue numbers by making them sequential + for res_num, seq_indices in positions_with_same_num.items(): + if len(seq_indices) > 1: + # Multiple residues have the same residue number + # Make them sequential starting from the original number + seq_indices.sort() # Ensure consistent ordering + for i, seq_idx in enumerate(seq_indices): + original_pos = residue_data[seq_idx] + new_pos = Residue( + residue_number=res_num + i, + insertion_code=original_pos.insertion_code, + hetflag=original_pos.hetflag, + ) + residue_data[seq_idx] = new_pos + + # Create ordered mappings using author chain IDs + for asym_id in chain_data: + auth_chain_id = asym_to_auth_mapping.get(asym_id, asym_id) + if auth_chain_id in self.chain_to_seqres: + seq_len = len(self.chain_to_seqres[auth_chain_id]) + ordered_mapping = {} + + for i in range(seq_len): + if i in chain_data[asym_id]: + ordered_mapping[i] = chain_data[asym_id][i] + else: + # Missing residue - no structure coordinates + ordered_mapping[i] = Residue( + residue_number=None, insertion_code="", hetflag=False + ) + + self.seqres_to_structure[auth_chain_id] = ordered_mapping + else: + # Handle case where auth_chain_id is not in chain_to_seqres + # This can happen if the chain is not a polymer or if there's a parsing issue + # Create a basic mapping based on the chain_data + if chain_data[asym_id]: + # Sort by sequence index to create ordered mapping + sorted_indices = sorted(chain_data[asym_id].keys()) + ordered_mapping = {} + for i, seq_idx in enumerate(sorted_indices): + ordered_mapping[i] = chain_data[asym_id][seq_idx] + self.seqres_to_structure[auth_chain_id] = ordered_mapping + + # Ensure all chains have complete mappings + for chain_id in self.chain_to_seqres: + if chain_id not in self.seqres_to_structure: + seq_len = len(self.chain_to_seqres[chain_id]) + self.seqres_to_structure[chain_id] = { + i: Residue(residue_number=None, insertion_code="", hetflag=False) + for i in range(seq_len) + } + else: + # Fill in any missing indices + seq_len = len(self.chain_to_seqres[chain_id]) + mapping = self.seqres_to_structure[chain_id] + for i in range(seq_len): + if i not in mapping: + mapping[i] = Residue( + residue_number=None, insertion_code="", hetflag=False + ) + + # Fallback: create basic mappings from structure for missing chains + if ( + self.structure + and hasattr(self.structure, "chain_id") + and self.structure.chain_id is not None + and hasattr(self.structure.chain_id, "__iter__") + ): + for chain_id in set(self.structure.chain_id): + if chain_id not in self.seqres_to_structure: + chain_structure = self.structure[ + self.structure.chain_id == chain_id + ] + if ( + hasattr(chain_structure, "res_id") + and chain_structure.res_id is not None + and hasattr(chain_structure.res_id, "__iter__") + ): + residue_ids = list(set(chain_structure.res_id)) + residue_ids.sort() + + self.seqres_to_structure[chain_id] = { + i: Residue( + residue_number=res_id, insertion_code="", hetflag=False + ) + for i, res_id in enumerate(residue_ids) + } + + def _parse_nonpoly_from_mmcif(self) -> dict[tuple, bs.AtomArray]: + """Parse non-polymer coordinates from mmCIF block data.""" + nonpoly_coords = {} + + # Get non-polymer entities from the mmCIF block + assert self.raw is not None + block = self.raw.block + nonpoly_entities = set() + + # Find non-polymer entities + if "entity" in block: + entity_cat = block["entity"] + entity_ids = entity_cat["id"].as_array(str) + entity_types = entity_cat["type"].as_array(str) + + for entity_id, entity_type in zip(entity_ids, entity_types): + if entity_type.upper() in ["NON-POLYMER", "WATER", "BRANCHED"]: + nonpoly_entities.add(entity_id) + + # Map entities to chains for non-polymers + entity_to_chains = {} + if "pdbx_entity_nonpoly" in block: + nonpoly_cat = block["pdbx_entity_nonpoly"] + entity_ids = nonpoly_cat["entity_id"].as_array(str) + comp_ids = nonpoly_cat["comp_id"].as_array(str) + + for entity_id, comp_id in zip(entity_ids, comp_ids): + if entity_id in nonpoly_entities: + entity_to_chains[entity_id] = comp_id + + # Get atom site information for non-polymers + if "atom_site" in block: + atom_cat = block["atom_site"] + atom_chain_ids = atom_cat["label_asym_id"].as_array(str) + atom_entity_ids = atom_cat["label_entity_id"].as_array(str) + atom_comp_ids = atom_cat["label_comp_id"].as_array(str) + + # Group non-polymer atoms by entity and chain + nonpoly_atom_groups = {} + for i, (chain_id, entity_id, comp_id) in enumerate( + zip(atom_chain_ids, atom_entity_ids, atom_comp_ids) + ): + if entity_id in nonpoly_entities: + key = (comp_id, chain_id) + if key not in nonpoly_atom_groups: + nonpoly_atom_groups[key] = [] + nonpoly_atom_groups[key].append(i) + + # Extract coordinates for each non-polymer group + for (comp_id, chain_id), atom_indices in nonpoly_atom_groups.items(): + # Match atoms by comparing chain_id and residue name + structure_mask = (self.structure.chain_id == chain_id) & ( + self.structure.res_name == comp_id + ) + + if structure_mask.any(): + nonpoly_array = self.structure[structure_mask] + if ( + isinstance(nonpoly_array, (bs.AtomArray, bs.AtomArrayStack)) + and len(nonpoly_array) > 0 + ): + nonpoly_coords[(comp_id, chain_id)] = nonpoly_array + + return nonpoly_coords + + def _parse_nonpoly_fallback(self) -> dict[tuple, bs.AtomArray]: + """Fallback method to extract heteroatoms directly from structure.""" + nonpoly_coords = {} + + if not (self.structure and hasattr(self.structure, "chain_id")): + return nonpoly_coords + + # Create set of standard residues from residue_constants + standard_residues = set(residue_constants.resnames[:-1]) # Exclude 'UNK' + standard_residues.update({"A", "C", "G", "T", "U"}) # Add nucleic acids + + if hasattr(self.structure, "chain_id") and self.structure.chain_id is not None: + for chain_id in set(self.structure.chain_id): + chain_structure = self.structure[self.structure.chain_id == chain_id] + + # Find non-standard residues + if ( + hasattr(chain_structure, "res_name") + and chain_structure.res_name is not None + and hasattr(chain_structure.res_name, "__iter__") + ): + for res_name in set(chain_structure.res_name): + if res_name not in standard_residues: + res_mask = (chain_structure.chain_id == chain_id) & ( + chain_structure.res_name == res_name + ) + if res_mask.any() and isinstance( + chain_structure, (bs.AtomArray, bs.AtomArrayStack) + ): + nonpoly_array = chain_structure[res_mask] + nonpoly_coords[(res_name, chain_id)] = nonpoly_array + + return nonpoly_coords + + @functools.cached_property + def non_polymer_coords(self) -> dict[tuple, bs.AtomArray]: + """ + Extract non-polymer coordinates (ligands, cofactors, etc.) from mmCIF structure. + + Returns a dictionary mapping (nonpolymer_info, chain_id) tuples to AtomArrays. + """ + if not self.structure or not self.raw: + return {} + + try: + return self._parse_nonpoly_from_mmcif() + except Exception: + return self._parse_nonpoly_fallback() diff --git a/esm/utils/structure/protein_chain.py b/esm/utils/structure/protein_chain.py index 4fcc5dfd..4889886e 100644 --- a/esm/utils/structure/protein_chain.py +++ b/esm/utils/structure/protein_chain.py @@ -1,10 +1,11 @@ from __future__ import annotations import io +import warnings from dataclasses import asdict, dataclass, replace from functools import cached_property from pathlib import Path -from typing import Sequence, TypeVar, Union +from typing import Any, Mapping, Sequence import biotite.structure as bs import brotli @@ -12,51 +13,36 @@ import msgpack_numpy import numpy as np import torch -from Bio.Data import PDBData -from biotite.application.dssp import DsspApp from biotite.database import rcsb from biotite.structure.io.pdb import PDBFile -from cloudpathlib import CloudPath -from scipy.spatial import ConvexHull -from scipy.spatial.distance import pdist, squareform -from torch import Tensor +from biotite.structure.io.pdbx import CIFCategory, CIFColumn, CIFData, CIFFile +from biotite.structure.io.pdbx import set_structure as set_structure_pdbx +from scipy.spatial import ConvexHull, KDTree +from scipy.spatial.distance import cdist, pdist, squareform -from esm.utils import residue_constants as RC -from esm.utils.constants import esm3 as C +from esm.utils import residue_constants from esm.utils.misc import slice_python_object_as_numpy from esm.utils.structure.affine3d import Affine3D from esm.utils.structure.aligner import Aligner -from esm.utils.structure.metrics import compute_lddt_ca +from esm.utils.structure.atom_indexer import AtomIndexer +from esm.utils.structure.metrics import compute_gdt_ts, compute_lddt_ca +from esm.utils.structure.mmcif_parsing import MmcifWrapper, Residue from esm.utils.structure.normalize_coordinates import ( apply_frame_to_coords, get_protein_normalization_frame, - normalize_coordinates, ) +from esm.utils.structure.protein_structure import index_by_atom_name +from esm.utils.types import PathOrBuffer msgpack_numpy.patch() - CHAIN_ID_CONST = "A" -ArrayOrTensor = TypeVar("ArrayOrTensor", np.ndarray, Tensor) -PathLike = Union[str, Path, CloudPath] -PathOrBuffer = Union[PathLike, io.StringIO] - - -def index_by_atom_name( - atom37: ArrayOrTensor, atom_names: str | list[str], dim: int = -2 -) -> ArrayOrTensor: - squeeze = False - if isinstance(atom_names, str): - atom_names = [atom_names] - squeeze = True - indices = [RC.atom_order[atom_name] for atom_name in atom_names] - dim = dim % atom37.ndim - index = tuple(slice(None) if dim != i else indices for i in range(atom37.ndim)) - result = atom37[index] # type: ignore - if squeeze: - result = result.squeeze(dim) - return result +def _num_non_null_residues(seqres_to_structure_chain: Mapping[int, Residue]) -> int: + return sum( + residue.residue_number is not None + for residue in seqres_to_structure_chain.values() + ) def infer_CB(C, N, Ca, L: float = 1.522, A: float = 1.927, D: float = -2.143): @@ -78,34 +64,84 @@ def infer_CB(C, N, Ca, L: float = 1.522, A: float = 1.927, D: float = -2.143): return Ca + sum([m * d for m, d in zip(m, d)]) -class AtomIndexer: - def __init__(self, structure: ProteinChain, property: str, dim: int): - self.structure = structure - self.property = property - self.dim = dim - - def __getitem__(self, atom_names: str | list[str]) -> np.ndarray: - return index_by_atom_name( - getattr(self.structure, self.property), atom_names, self.dim - ) - - -@dataclass +def chain_to_ndarray( + atom_array: bs.AtomArray, mmcif: MmcifWrapper, chain_id: str, is_predicted=False +): + entity_id = None + for entity, chains in mmcif.entities.items(): + if chain_id in chains: + entity_id = entity + num_res = len(mmcif.chain_to_seqres[chain_id]) + sequence = mmcif.chain_to_seqres[chain_id] + + atom_positions = np.full([num_res, residue_constants.atom_type_num, 3], np.nan) + atom_mask = np.full([num_res, residue_constants.atom_type_num], False, dtype=bool) + residue_index = np.full([num_res], -1, dtype=np.int64) + insertion_code = np.full([num_res], "", dtype=" bs.AtomArray: chain_id="A" if self.chain_id is None else self.chain_id, res_id=res_idx, ins_code=ins_code, - res_name=RC.restype_1to3.get(res_name, "UNK"), + res_name=residue_constants.restype_1to3.get(res_name, "UNK"), hetero=False, - atom_name=RC.atom_types[i], - element=RC.atom_types[i][0], + atom_name=residue_constants.atom_types[i], + element=residue_constants.atom_types[i][0], b_factor=conf, ) atoms.append(atom) @@ -182,18 +218,20 @@ def atom_array_no_insertions(self) -> bs.AtomArray: # hard coded to as we currently only support single chain structures chain_id=CHAIN_ID_CONST, res_id=res_idx + 1, - res_name=RC.restype_1to3.get(res_name, "UNK"), + res_name=residue_constants.restype_1to3.get(res_name, "UNK"), hetero=False, - atom_name=RC.atom_types[i], - element=RC.atom_types[i][0], + atom_name=residue_constants.atom_types[i], + element=residue_constants.atom_types[i][0], b_factor=conf, ) atoms.append(atom) return bs.array(atoms) - def __getitem__(self, idx: int | list[int] | slice | np.ndarray): + def __getitem__(self, idx: int | list[int] | slice | np.ndarray | torch.Tensor): if isinstance(idx, int): idx = [idx] + if isinstance(idx, torch.Tensor): + idx = idx.cpu().numpy() sequence = slice_python_object_as_numpy(self.sequence, idx) return replace( @@ -216,17 +254,6 @@ def cbeta_contacts(self, distance_threshold: float = 8.0) -> np.ndarray: np.fill_diagonal(contacts, -1) return contacts - def to_structure_encoder_inputs( - self, should_normalize_coordinates: bool = True - ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]: - coords = torch.tensor(self.atom37_positions, dtype=torch.float32) - plddt = torch.tensor(self.confidence, dtype=torch.float32) - residue_index = torch.tensor(self.residue_index, dtype=torch.long) - - if should_normalize_coordinates: - coords = normalize_coordinates(coords) - return coords.unsqueeze(0), plddt.unsqueeze(0), residue_index.unsqueeze(0) - def to_pdb(self, path: PathOrBuffer, include_insertions: bool = True): """Dssp works better w/o insertions.""" f = PDBFile() @@ -242,11 +269,77 @@ def to_pdb_string(self, include_insertions: bool = True) -> str: buf.seek(0) return buf.read() + def to_mmcif(self, path: PathOrBuffer): + f = CIFFile() + set_structure_pdbx(f, self.atom_array, data_block=self.id) + + # incantations molstar needs to render pLDDT / confidence onto + # the structure with "alphafold-view" + f.block["ma_qa_metric"] = CIFCategory( + name="ma_qa_metric", + columns={ + "id": CIFColumn(data=CIFData(array=np.array([1, 2]), dtype=np.int64)), + "mode": CIFColumn( + data=CIFData(array=np.array(["global", "local"]), dtype=np.str_) + ), + "name": CIFColumn( + data=CIFData(array=np.array(["pLDDT", "pLDDT"]), dtype=np.str_) + ), + }, + ) + + # table is a duplicate of data already in the atom array, but + # needed by molstar to render pLDDT / confidence + resid_pldd_table = { + # hard coded to as we currently only support single chain structures + "label_asym_id": CIFColumn( + data=CIFData( + array=[CHAIN_ID_CONST] * len(self.residue_index), dtype=np.str_ + ) + ), + "label_comp_id": CIFColumn( + data=CIFData( + array=[ + residue_constants.restype_1to3.get(c, "UNK") + for c in self.sequence + ], + dtype=np.str_, + ) + ), + "label_seq_id": CIFColumn( + data=CIFData(array=self.residue_index, dtype=np.int64) + ), + "ordinal_id": CIFColumn( + data=CIFData(array=self.residue_index, dtype=np.int64) + ), + # hard coded to show these are all local plDDT values + "metric_id": CIFColumn( + data=CIFData(array=["2"] * len(self.residue_index), dtype=np.str_) + ), + "metric_value": CIFColumn( + data=CIFData(array=self.confidence, dtype=np.float32) + ), + # hard coded to show there are the initial version, there are no revisions + "model_id": CIFColumn( + data=CIFData(array=["1"] * len(self.residue_index), dtype=np.str_) + ), + } + f.block["ma_qa_metric_local"] = CIFCategory( + name="ma_qa_metric_local", columns=resid_pldd_table + ) + f.write(path) + + def to_mmcif_string(self) -> str: + buf = io.StringIO() + self.to_mmcif(buf) + buf.seek(0) + return buf.read() + def state_dict(self, backbone_only=False, json_serializable=False): """This state dict is optimized for storage, so it turns things to fp16 whenever possible. Note that we also only support int32 residue indices, I'm hoping we don't need more than 2**32 residues...""" - dct = {k: v for k, v in asdict(self).items()} + dct = {k: v for k, v in asdict(self).items() if k not in ["mmcif"]} if backbone_only: dct["atom37_mask"][:, 3:] = False dct["atom37_positions"] = dct["atom37_positions"][dct["atom37_mask"]] @@ -265,7 +358,11 @@ def state_dict(self, backbone_only=False, json_serializable=False): return dct def to_blob(self, backbone_only=False) -> bytes: - return brotli.compress(msgpack.dumps(self.state_dict(backbone_only))) + return brotli.compress(msgpack.dumps(self.state_dict(backbone_only)), quality=5) + + @classmethod + def from_open_source(cls, pc: ProteinChain): + return cls(**vars(pc)) @classmethod def from_state_dict(cls, dct): @@ -280,11 +377,11 @@ def from_state_dict(cls, dct): k: (v.astype(np.float32) if k in ["atom37_positions", "confidence"] else v) for k, v in dct.items() } - return cls(**dct) + return cls(**dct, mmcif=None) @classmethod def from_blob(cls, input: Path | str | io.BytesIO | bytes): - """NOTE: blob + sparse coding + brotli + fp16 reduces memory + """NOTE(@zlin): blob + sparse coding + brotli + fp16 reduces memory of chains from 52G/1M chains to 20G/1M chains, I think this is a good first shot at compressing and dumping chains to disk. I'm sure there's better ways.""" match input: @@ -296,24 +393,105 @@ def from_blob(cls, input: Path | str | io.BytesIO | bytes): bytes = input return cls.from_state_dict(msgpack.loads(brotli.decompress(bytes))) - def dssp(self): - dssp = DsspApp.annotate_sse(self.atom_array_no_insertions) - full_dssp = np.full(len(self.sequence), "X", dtype=" np.ndarray: + """Computes per-atom SAP score. + Can optionally aggregate by residue (by averaging over atoms. NOTE: this returns values only for residues that have coordinates!) + or full-protein (sum of SAP score for atoms with SAP > 0, as in Lauer et al. 2011).""" + sap_radius = 5.0 + arr = self.atom_array_no_insertions + + # asserts to avoid type errors assert arr.res_id is not None - assert np.array_equal( - np.sort(np.unique(arr.res_id)), np.arange(1, arr.res_id.max() + 1) - ), "SASA calculation expected contiguous res_ids in range(1, len(chain)+1)" - # NOTE: arr.res_id is 1-indexed, but np.bincount returns a sum for bin 0, so we strip. - sasa_per_residue = np.bincount(arr.res_id, weights=sasa_per_atom)[1:] - assert len(sasa_per_residue) == len(self) - return sasa_per_residue + assert arr.res_name is not None + assert arr.atom_name is not None + assert arr.coord is not None + + # compute SASA and residue-specific properties + sasa_per_atom = self.sasa(by_residue=False) + resid_to_resname = dict(zip(arr.res_id, arr.res_name)) + + max_side_chain_asa = np.full(len(self), np.nan) + res_hydrophobicity = np.full(len(self), np.nan) + resolved_res_mask = self.atom37_mask.any(-1) + num_trailing_residues = len(self) - arr.res_id.max() + + max_side_chain_asa[resolved_res_mask] = np.array( + [ + residue_constants.side_chain_asa[resid_to_resname[i]] + for i in np.unique(arr.res_id) + ] + ) + res_hydrophobicity[resolved_res_mask] = np.array( + [ + residue_constants.hydrophobicity[resid_to_resname[i]] + for i in np.unique(arr.res_id) + ] + ) + assert len(max_side_chain_asa) == len(self) + assert len(res_hydrophobicity) == len(self) + + # compute SAP score + is_side_chain = ~bs.filter_peptide_backbone(arr) + sasa_per_atom[is_side_chain] = 0 + kdtree = KDTree(arr.coord) + neighbors = kdtree.query_ball_tree(kdtree, sap_radius, p=2.0) + sap_by_atom = np.zeros_like(sasa_per_atom) + for i, nn_list in enumerate(neighbors): + saa_nn = np.zeros_like(sasa_per_atom) + saa_nn[nn_list] = sasa_per_atom[nn_list] + sasa_within_r = np.concatenate( + [ + np.bincount(arr.res_id, weights=saa_nn)[1:], + np.zeros(num_trailing_residues), + ] + ) + sap = np.nansum((sasa_within_r / max_side_chain_asa) * res_hydrophobicity) + sap_by_atom[i] = sap + + match aggregation: + case "atom": + return sap_by_atom + case "residue": + sap_by_residue = np.concatenate( + [ + np.bincount(arr.res_id, weights=sap_by_atom)[1:], + np.zeros(num_trailing_residues), + ] + ) / ( + np.concatenate( + [np.bincount(arr.res_id)[1:], np.zeros(num_trailing_residues)] + ) + + 1e-8 + ) + sap_by_residue[~resolved_res_mask] = np.nan + assert len(sap_by_residue) == len(self) + return sap_by_residue + case "protein": + return sum(sap_by_atom[sap_by_atom > 0]) # pyright: ignore[reportReturnType] + case _: + raise ValueError( + f"Invalid aggregation method: {aggregation}. Must be one of 'atom', 'residue', or 'protein'" + ) def globularity(self) -> float: # Computes globularity using total volumes divided by MVEE. @@ -325,10 +503,10 @@ def globularity(self) -> float: # NOTE(@zeming): due to the approximation we make here, that atoms never overlap, you might get >1 globularity mask = self.atom37_mask.any(-1) points = self.atom37_positions[self.atom37_mask] - sequence = [aa for aa, m in zip(self.sequence, mask) if m] + sequence = [aa for aa, m in zip(self.sequence, mask) if m] # type: ignore A, _ = self._mvee(points, tol=1e-3) mvee_volume = (4 * np.pi) / (3 * np.sqrt(np.linalg.det(A))) - volume = sum(RC.amino_acid_volumes[x] for x in sequence) + volume = sum(residue_constants.amino_acid_volumes[x] for x in sequence) ratio = volume / mvee_volume # The paper says you must compare the ellipsoidal profile with T, a measurement of @@ -388,6 +566,10 @@ def _mvee(P: np.ndarray, tol, max_iter=10000): return A, c + def radius_of_gyration(self): + arr = self.atom_array_no_insertions + return bs.gyration_radius(arr) + def align( self, target: ProteinChain, @@ -462,8 +644,8 @@ def lddt_ca( target_inds: list[int] | np.ndarray | None = None, **kwargs, ) -> float | np.ndarray: - """Compute the LDDT between this protein chain and another. - NOTE: LDDT IS NOT SYMMETRIC. The call should always be prediction.lddt_ca(native). + """Compute the LDDT between this protein chain and another. NOTE: LDDT IS NOT SYMMETRIC. + The call should always be prediction.lddt_ca(native). Arguments: native (ProteinChain): The ground truth protein chain @@ -482,6 +664,171 @@ def lddt_ca( ) return float(lddt) if lddt.numel() == 1 else lddt.numpy().flatten() + def gdt_ts( + self, + target: ProteinChain, + mobile_inds: list[int] | np.ndarray | None = None, + target_inds: list[int] | np.ndarray | None = None, + **kwargs, + ) -> float | np.ndarray: + """Compute the GDT_TS between this protein chain and another. + + Arguments: + target (ProteinChain): The other protein chain to compare to. + mobile_inds (list[int], np.ndarray, optional): The indices of the mobile atoms to align. These are NOT residue indices + target_inds (list[int], np.ndarray, optional): The indices of the target atoms to align. These are NOT residue indices + + Returns: + float: The GDT_TS score between the two protein chains. + """ + gdt_ts = compute_gdt_ts( + mobile=torch.tensor( + index_by_atom_name(self.atom37_positions[mobile_inds], "CA"), + dtype=torch.float32, + ).unsqueeze(0), + target=torch.tensor( + index_by_atom_name(target.atom37_positions[target_inds], "CA"), + dtype=torch.float32, + ).unsqueeze(0), + atom_exists_mask=torch.tensor( + index_by_atom_name(self.atom37_mask[mobile_inds], "CA", dim=-1) + & index_by_atom_name(target.atom37_mask[target_inds], "CA", dim=-1) + ).unsqueeze(0), + **kwargs, + ) + return float(gdt_ts) if gdt_ts.numel() == 1 else gdt_ts.numpy().flatten() + + @classmethod + def chain_iterable_from_mmcif( + cls, + path: PathOrBuffer | MmcifWrapper, + id: str | None = None, + is_predicted: bool = False, + keep_source: bool = False, + ): + """Return a list[ProteinChain] object from an mmcif file, a iterable list of all protein chain + from an mmcif file + """ + if isinstance(path, MmcifWrapper): + mmcif = path + else: + mmcif = MmcifWrapper.read(path, id) + for chain in bs.chain_iter(mmcif.structure): + chain = chain[bs.filter_amino_acids(chain) & ~chain.hetero] + if len(chain) == 0: + continue + chain_id = chain.chain_id[0] + entity_id = None + for entity, chains in mmcif.entities.items(): + if chain_id in chains: + entity_id = entity + assert entity_id is not None + ( + sequence, + atom_positions, + atom_mask, + residue_index, + insertion_code, + confidence, + _, + ) = chain_to_ndarray(chain, mmcif, chain_id, is_predicted) + assert all(sequence), "Some residue name was not specified correctly" + + yield cls( + id=mmcif.id, + sequence=sequence, + chain_id=chain_id, + entity_id=entity_id, + atom37_positions=atom_positions, + atom37_mask=atom_mask, + residue_index=residue_index, + insertion_code=insertion_code, + confidence=confidence, + mmcif=mmcif if keep_source else None, + ) + + @classmethod + def from_mmcif( + cls, + path: PathOrBuffer | MmcifWrapper, + chain_id: str | None = None, + entity_id: int | None = None, + id: str | None = None, + is_predicted: bool = False, + keep_source: bool = False, + ): + """Return a ProteinChain object from an mmcif file. + + Args: + path (str | Path | io.TextIO): Path or buffer to read mmcif file from. Should be uncompressed. + id (str, optional): String identifier to assign to structure. Will attempt to infer otherwise. + is_predicted (bool): If True, reads b factor as the confidence readout. Default: False. + chain_id (str, optional): Select a chain corresponding to (author) chain id. + entity_id (int, optional): Select a chain corresponding to a particular entity. + + If neither `chain_id` nor `entity_id` is specified, defaults to the first entity. + """ + if isinstance(path, MmcifWrapper): + mmcif = path + else: + mmcif = MmcifWrapper.read(path, id) + + # If neither chain_id nor entity_id is specified, default to the first entity + if chain_id is None and entity_id is None: + if not mmcif.entities: + raise ValueError("Structure contains no entities") + entity_id = min(mmcif.entities.keys()) # Pick the first entity by ID + + if entity_id is not None: + assert chain_id is None + if entity_id not in mmcif.entities: + raise ValueError( + f"Structure does not contain entity `{entity_id}`. Valid entities: {mmcif.entities.keys()}" + ) + chains = mmcif.entities[entity_id] + + # Select the chain id corresponding to the longest chain. If all are equal length, selects the first. + chain_id = max( + chains, + key=lambda chain: _num_non_null_residues( + mmcif.seqres_to_structure[chain] + ), + ) + else: + assert chain_id is not None + for entity, chains in mmcif.entities.items(): + if chain_id in chains: + entity_id = entity + if entity_id is None: + warnings.warn( + "Failed to detect entity_id from mmcif file, it may be malformed." + ) + + atom_array = mmcif.structure + ( + sequence, + atom_positions, + atom_mask, + residue_index, + insertion_code, + confidence, + _, + ) = chain_to_ndarray(atom_array, mmcif, chain_id, is_predicted) + assert all(sequence), "Some residue name was not specified correctly" + + return cls( + id=mmcif.id, + sequence=sequence, + chain_id=chain_id, + entity_id=entity_id, + atom37_positions=atom_positions, + atom37_mask=atom_mask.astype(bool), + residue_index=residue_index, + insertion_code=insertion_code, + confidence=confidence, + mmcif=mmcif if keep_source else None, + ) + @classmethod def from_atom37( cls, @@ -549,11 +896,11 @@ def from_atom37( return cls( id=id, - sequence=sequence, + sequence=sequence, # type: ignore chain_id=chain_id, entity_id=entity_id, atom37_positions=atom37_positions, - atom37_mask=atom_mask, + atom37_mask=atom_mask.astype(bool), residue_index=residue_index, insertion_code=insertion_code, confidence=confidence, @@ -604,10 +951,12 @@ def from_pdb( id: str | None = None, is_predicted: bool = False, ) -> "ProteinChain": - """Return a ProteinChain object from an pdb file. + """Return a ProteinChain object from an pdb file. NOTE: prefer mmcif for rcsb PDB files. + This function is mostly to interface with old PDB files and predicted structures - + it will not fill out the entity id correctly Args: - path (str | Path | io.TextIO): Path or buffer to read pdb file from. Should be uncompressed. + path (str | Path | io.TextIO): Path or buffer to read mmcif file from. Should be uncompressed. id (str, optional): String identifier to assign to structure. Will attempt to infer otherwise. is_predicted (bool): If True, reads b factor as the confidence readout. Default: False. chain_id (str, optional): Select a chain corresponding to (author) chain id. "detect" uses the @@ -637,20 +986,17 @@ def from_pdb( entity_id = 1 # Not supplied in PDBfiles sequence = "".join( - ( - r - if len(r := PDBData.protein_letters_3to1.get(monomer[0].res_name, "X")) - == 1 - else "X" - ) + residue_constants.restype_3to1.get(monomer[0].res_name, "X") for monomer in bs.residue_iter(atom_array) ) num_res = len(sequence) atom_positions = np.full( - [num_res, RC.atom_type_num, 3], np.nan, dtype=np.float32 + [num_res, residue_constants.atom_type_num, 3], np.nan, dtype=np.float32 + ) + atom_mask = np.full( + [num_res, residue_constants.atom_type_num], False, dtype=bool ) - atom_mask = np.full([num_res, RC.atom_type_num], False, dtype=bool) residue_index = np.full([num_res], -1, dtype=np.int64) insertion_code = np.full([num_res], "", dtype=" "ProteinChain": + return cls( + id=data["id"], + chain_id=data["chain_id"], + entity_id=data["entity_id"], + sequence=data["sequence"], + residue_index=data["residue_index"], + insertion_code=np.asarray(data["insertion_code"]), + atom37_positions=data["atom37_positions"], + atom37_mask=data["atom37_mask"].astype(bool), + confidence=data["confidence"], + mmcif=None, ) @classmethod - def from_rcsb(cls, pdb_id: str, chain_id: str = "detect"): - """Fetch a protein chain from the RCSB PDB database.""" - f: io.StringIO = rcsb.fetch(pdb_id, "pdb") # type: ignore - return cls.from_pdb(f, chain_id=chain_id, id=pdb_id) + def from_rcsb( + cls, + pdb_id: str, + chain_id: str | None = None, + entity_id: int | None = None, + keep_source: bool = False, + ) -> ProteinChain: + f: io.StringIO = rcsb.fetch(pdb_id, "cif") # type: ignore + return cls.from_mmcif( + f, + id=pdb_id, + chain_id=chain_id, + entity_id=entity_id, + keep_source=keep_source, + is_predicted=False, + ) @classmethod def from_atomarray( - cls, atom_array: bs.AtomArray, id: str | None = None + cls, atom_array: bs.AtomArray, id: str | None = None, is_predicted: bool = False ) -> "ProteinChain": """A simple converter from bs.AtomArray -> ProteinChain. Uses PDB file format as intermediate.""" @@ -711,7 +1087,7 @@ def from_atomarray( buf = io.StringIO() pdb_file.write(buf) buf.seek(0) - return cls.from_pdb(buf, id=id) + return cls.from_pdb(buf, id=id, is_predicted=is_predicted) def get_normalization_frame(self) -> Affine3D: """Given a set of coordinates, compute a single frame. @@ -745,6 +1121,8 @@ def normalize_coordinates(self) -> ProteinChain: def infer_oxygen(self) -> ProteinChain: """Oxygen position is fixed given N, CA, C atoms. Infer it if not provided.""" + O_missing_indices = np.argwhere(np.isnan(self.atoms["O"]).any(axis=1)).squeeze() + O_vector = torch.tensor([0.6240, -1.0613, 0.0103], dtype=torch.float32) N, CA, C = torch.from_numpy(self.atoms[["N", "CA", "C"]]).float().unbind(dim=1) N = torch.roll(N, -3) @@ -756,9 +1134,11 @@ def infer_oxygen(self) -> ProteinChain: atom37_positions = self.atom37_positions.copy() atom37_mask = self.atom37_mask.copy() - atom37_positions[:, RC.atom_order["O"]] = O.numpy() - atom37_mask[:, RC.atom_order["O"]] = ~np.isnan( - atom37_positions[:, RC.atom_order["O"]] + atom37_positions[O_missing_indices, residue_constants.atom_order["O"]] = O[ + O_missing_indices + ].numpy() + atom37_mask[O_missing_indices, residue_constants.atom_order["O"]] = ~np.isnan( + atom37_positions[O_missing_indices, residue_constants.atom_order["O"]] ).any(-1) new_chain = replace( self, atom37_positions=atom37_positions, atom37_mask=atom37_mask @@ -781,7 +1161,7 @@ def infer_cbeta(self, infer_cbeta_for_glycine: bool = False) -> ProteinChain: infer_cbeta_for_glycine (bool): If True, infers a beta carbon for glycine residues, even though that residue doesn't have one. Default off. - NOTE: The reason for having this switch in the first place + NOTE(rverkuil): The reason for having this switch in the first place is that sometimes we want a (inferred) CB coordinate for every residue, for example for making a pairwise distance matrix, or doing an RMSD calculation between two designs for a given structural template, w/ @@ -792,11 +1172,13 @@ def infer_cbeta(self, infer_cbeta_for_glycine: bool = False) -> ProteinChain: inferred_cbeta_positions = self.inferred_cbeta if not infer_cbeta_for_glycine: - inferred_cbeta_positions[np.array(list(self.sequence)) == "G", :] = np.NAN + inferred_cbeta_positions[np.array(list(self.sequence)) == "G", :] = np.nan - atom37_positions[:, RC.atom_order["CB"]] = inferred_cbeta_positions - atom37_mask[:, RC.atom_order["CB"]] = ~np.isnan( - atom37_positions[:, RC.atom_order["CB"]] + atom37_positions[:, residue_constants.atom_order["CB"]] = ( + inferred_cbeta_positions + ) + atom37_mask[:, residue_constants.atom_order["CB"]] = ~np.isnan( + atom37_positions[:, residue_constants.atom_order["CB"]] ).any(-1) new_chain = replace( self, atom37_positions=atom37_positions, atom37_mask=atom37_mask @@ -822,36 +1204,69 @@ def as_complex(cls, chains: Sequence[ProteinChain]): ) @classmethod - def concat(cls, chains: Sequence[ProteinChain]): - def join_arrays(arrays: Sequence[np.ndarray], sep: np.ndarray): - full_array = [] - for array in arrays: - full_array.append(array) - full_array.append(sep) - full_array = full_array[:-1] - return np.concatenate(full_array, 0) - + def concat(cls, chains: Sequence[ProteinChain], use_chainbreak: bool = True): sep_tokens = { "residue_index": np.array([-1]), "insertion_code": np.array([""]), - "atom37_positions": np.full([1, 37, 3], np.nan), - "atom37_mask": np.zeros([1, 37]), + "atom37_positions": np.full([1, 37, 3], np.inf), + "atom37_mask": np.zeros([1, 37], dtype=bool), "confidence": np.array([0]), } + def join_arrays(arrays: Sequence[np.ndarray], sep: np.ndarray): + if use_chainbreak: + full_array = [] + for array in arrays: + full_array.append(array) + full_array.append(sep) + full_array = full_array[:-1] + return np.concatenate(full_array, 0) + else: + return np.concatenate(arrays, 0) + array_args: dict[str, np.ndarray] = { name: join_arrays([getattr(chain, name) for chain in chains], sep) for name, sep in sep_tokens.items() } + chain_break = residue_constants.CHAIN_BREAK_TOKEN if use_chainbreak else "" return cls( id=chains[0].id, - sequence=C.CHAIN_BREAK_STR.join(chain.sequence for chain in chains), + sequence=chain_break.join(chain.sequence for chain in chains), chain_id="A", entity_id=None, + mmcif=None, **array_args, ) + def find_nonpolymer_contacts(self): + assert self.mmcif is not None + nonpolymer_and_chain_id_to_array = self.mmcif.non_polymer_coords + + results = [] + for ( + nonpolymer, + _, + ), nonpolymer_array in nonpolymer_and_chain_id_to_array.items(): + assert nonpolymer_array.coord is not None + chain_coords = self.atom37_positions[self.atom37_mask] + distance = cdist(nonpolymer_array.coord, chain_coords) + + is_contact = distance < 5 + if not is_contact.any(): + continue + contacting_atoms = np.where(is_contact.any(0))[0] + chain_index = np.where(self.atom37_mask)[0] + contacting_residues = np.unique(chain_index[contacting_atoms]) + + result = { + "ligand": nonpolymer.name, + "ligand_id": nonpolymer.comp_id, + "contacting_residues": contacting_residues.tolist(), + } + results.append(result) + return results + def select_residue_indices( self, indices: list[int | str], ignore_x_mismatch: bool = False ) -> ProteinChain: @@ -876,3 +1291,25 @@ def select_residue_indices( raise RuntimeError(mismatch_str) return new + + def to_structure_encoder_inputs( + self, + ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]: + """Convert protein chain to structure encoder inputs. + + Returns: + tuple: (coordinates, plddt, residue_index) where: + - coordinates: (1, L, 37, 3) tensor of atom positions + - plddt: (1, L) tensor of confidence scores + - residue_index: (1, L) tensor of residue indices + """ + # Convert to tensors and add batch dimension + coordinates = ( + torch.from_numpy(self.atom37_positions).float().unsqueeze(0) + ) # (1, L, 37, 3) + plddt = torch.from_numpy(self.confidence).float().unsqueeze(0) # (1, L) + residue_index = ( + torch.from_numpy(self.residue_index).long().unsqueeze(0) + ) # (1, L) + + return coordinates, plddt, residue_index diff --git a/esm/utils/structure/protein_complex.py b/esm/utils/structure/protein_complex.py index aa27017c..7e2c38de 100644 --- a/esm/utils/structure/protein_complex.py +++ b/esm/utils/structure/protein_complex.py @@ -2,6 +2,7 @@ import io import itertools +import random import re import warnings from dataclasses import asdict, dataclass, replace @@ -18,24 +19,28 @@ import numpy as np import torch from biotite.database import rcsb +from biotite.file import InvalidFileError from biotite.structure.io.pdb import PDBFile +from biotite.structure.io.pdbx import CIFCategory, CIFColumn, CIFData, CIFFile +from biotite.structure.io.pdbx import set_structure as set_structure_pdbx +from biotite.structure.io.pdbx.convert import _get_transformations, get_structure +from biotite.structure.util import matrix_rotate +from scipy.spatial import KDTree from esm.utils import residue_constants -from esm.utils.constants import esm3 as esm3_c from esm.utils.misc import slice_python_object_as_numpy from esm.utils.structure.affine3d import Affine3D from esm.utils.structure.aligner import Aligner -from esm.utils.structure.metrics import ( - compute_gdt_ts, - compute_lddt_ca, -) +from esm.utils.structure.atom_indexer import AtomIndexer +from esm.utils.structure.metrics import compute_gdt_ts, compute_lddt_ca +from esm.utils.structure.mmcif_parsing import MmcifWrapper, NoProteinError from esm.utils.structure.protein_chain import ( - PathOrBuffer, ProteinChain, -) -from esm.utils.structure.protein_structure import ( + chain_to_ndarray, index_by_atom_name, + infer_CB, ) +from esm.utils.types import PathOrBuffer msgpack_numpy.patch() @@ -44,35 +49,72 @@ ) -def protein_chain_to_protein_complex(chain: ProteinChain) -> ProteinComplex: - if "|" not in chain.sequence: - return ProteinComplex.from_chains([chain]) - chain_breaks = np.array(list(chain.sequence)) == "|" - chain_break_inds = np.where(chain_breaks)[0] - chain_break_inds = np.concatenate([[0], chain_break_inds, [len(chain)]]) - chain_break_inds = np.array(list(zip(chain_break_inds[:-1], chain_break_inds[1:]))) - complex_chains = [] - for start, end in chain_break_inds: - if start != 0: - start += 1 - complex_chains.append(chain[start:end]) - complex_chains = [ - ProteinChain.from_atom37( - chain.atom37_positions, - sequence=chain.sequence, - chain_id=SINGLE_LETTER_CHAIN_IDS[i], - entity_id=i, - ) - for i, chain in enumerate(complex_chains) - ] - return ProteinComplex.from_chains(complex_chains) +def _parse_operation_expression(expression): + """ + Get successive operation steps (IDs) for the given + ``oper_expression``. + Form the cartesian product, if necessary. + Copied from biotite and fixed a bug + """ + # Split groups by parentheses: + # use the opening parenthesis as delimiter + # and just remove the closing parenthesis + expressions_per_step = expression.replace(")", "").split("(") + expressions_per_step = [e for e in expressions_per_step if len(e) > 0] + # Important: Operations are applied from right to left + expressions_per_step.reverse() + + operations = [] + for expr in expressions_per_step: + cur_expr = expr.split(",") + cur_op = [] + # Deal with e='1-10,20-30,40-50' type expressions + for e in cur_expr: + if "-" in e: + first, last = e.split("-") + cur_op.extend(str(id) for id in range(int(first), int(last) + 1)) + else: + cur_op.append(e) + operations.append(cur_op) + + # Cartesian product of operations + return list(itertools.product(*operations)) + + +def _apply_transformations_fast(chains, transformation_dict, operations): + """ + Get subassembly by applying the given operations to the input + structure containing affected asym IDs. + """ + # Additional first dimesion for 'structure.repeat()' + results = [] + + # Apply corresponding transformation for each copy in the assembly + for c in chains: + for operation in operations: + coord = c.atom37_positions.copy() + # Execute for each transformation step + # in the operation expression + for op_step in operation: + T = transformation_dict[op_step] + # Rotate + coord = matrix_rotate(coord, T.rotation) + # Translate + coord += T.target_translation + new_chain = replace(c, atom37_positions=coord) + results.append(new_chain) + + return results @dataclass class ProteinComplexMetadata: entity_lookup: dict[int, int] chain_lookup: dict[int, str] - chain_boundaries: list[tuple[int, int]] + mmcif: MmcifWrapper | None = None + # This is a dictionary that maps assembly ids to the list of unique chains + # in that assembly. Allows for usage of `switch_assembly`. + assembly_composition: dict[str, list[str]] | None = None @dataclass @@ -100,19 +142,7 @@ class DockQResult: aligned_rmsd: float -class AtomIndexer: - def __init__(self, structure: ProteinComplex, property: str, dim: int): - self.structure = structure - self.property = property - self.dim = dim - - def __getitem__(self, atom_names: str | list[str]) -> np.ndarray: - return index_by_atom_name( - getattr(self.structure, self.property), atom_names, self.dim - ) - - -@dataclass +@dataclass(frozen=True) class ProteinComplex: """Dataclass with atom37 representation of an entire protein complex.""" @@ -126,6 +156,7 @@ class ProteinComplex: atom37_positions: np.ndarray atom37_mask: np.ndarray confidence: np.ndarray + # This metadata is parsed from the MMCIF file. For synthetic data, we do a best effort. metadata: ProteinComplexMetadata def __post_init__(self): @@ -195,15 +226,59 @@ def _unsafe_slice(self, idx: int | list[int] | slice | np.ndarray): def __len__(self): return len(self.sequence) + @property + def num_chains(self): + return len(self.chain_boundaries) + @cached_property def atoms(self) -> AtomIndexer: return AtomIndexer(self, property="atom37_positions", dim=-2) + @cached_property + def atom_mask(self) -> AtomIndexer: + return AtomIndexer(self, property="atom37_mask", dim=-1) + + @cached_property + def chain_lengths(self) -> np.ndarray: + return np.diff(self.chain_boundaries, axis=1).flatten() + + @cached_property + def chain_boundaries(self) -> list[tuple[int, int]]: + cb = [-1] + for i, s in enumerate(self.sequence): + if s == "|": + cb.append(i) + cb.append(len(self)) + return [(cb[i] + 1, cb[i + 1]) for i in range(len(cb) - 1)] + + def get_chain_by_index(self, index: int) -> ProteinChain: + try: + start, end = self.chain_boundaries[index] + return self[start:end].as_chain() + except IndexError: + raise IndexError(f"Chain index {index} out of bounds") + + def get_chain_by_id( + self, chain_id: str, sample_chain_if_duplicate: bool = True + ) -> ProteinChain: + valid_indices = [ + index + for index, id_of_index in self.metadata.chain_lookup.items() + if id_of_index == chain_id + ] + if not valid_indices: + raise KeyError(f"Chain ID {chain_id} not found") + if sample_chain_if_duplicate: + index_to_return = random.choice(valid_indices) + return self.get_chain_by_index(index_to_return) + else: + if len(valid_indices) > 1: + raise ValueError(f"Multiple chains with chain ID {chain_id} found") + return self.get_chain_by_index(valid_indices[0]) + def chain_iter(self) -> Iterable[ProteinChain]: - boundaries = [i for i, s in enumerate(self.sequence) if s == "|"] - boundaries = [-1, *boundaries, len(self)] - for i in range(len(boundaries) - 1): - c = self.__getitem__(slice(boundaries[i] + 1, boundaries[i + 1])) + for start, end in self.chain_boundaries: + c = self[start:end] yield c.as_chain() def as_chain(self, force_conversion: bool = False) -> ProteinChain: @@ -237,6 +312,7 @@ def as_chain(self, force_conversion: bool = False) -> ProteinChain: residue_index=self.residue_index, insertion_code=self.insertion_code, confidence=self.confidence, + mmcif=self.metadata.mmcif, ) @classmethod @@ -253,12 +329,6 @@ def from_pdb(cls, path: PathOrBuffer, id: str | None = None) -> "ProteinComplex" chains.append(ProteinChain.from_atomarray(chain, id)) return ProteinComplex.from_chains(chains) - @classmethod - def from_rcsb(cls, pdb_id: str): - """Fetch a protein complex from the RCSB PDB database.""" - f: io.StringIO = rcsb.fetch(pdb_id, "pdb") # type: ignore - return cls.from_pdb(f, id=pdb_id) - def to_pdb(self, path: PathOrBuffer, include_insertions: bool = True): atom_array = None for chain in self.chain_iter(): @@ -284,13 +354,29 @@ def normalize_chain_ids_for_pdb(self): ids = SINGLE_LETTER_CHAIN_IDS chains = [] for i, chain in enumerate(self.chain_iter()): - chain.chain_id = ids[i] + chain = replace(chain, chain_id=ids[i]) if i > len(ids): raise RuntimeError("Too many chains to write to PDB file") chains.append(chain) return ProteinComplex.from_chains(chains) + def find_assembly_ids_with_chain(self, id: str) -> list[str]: + good_chains = [] + if (comp := self.metadata.assembly_composition) is not None: + for assembly_id, chain_ids in comp.items(): + if id in chain_ids: + good_chains.append(assembly_id) + else: + raise ValueError( + "Cannot switch assemblies on this ProteinComplex, you must create the assembly from mmcif to support this" + ) + return good_chains + + def switch_assembly(self, id: str): + assert self.metadata.mmcif is not None + return get_assembly_fast(self.metadata.mmcif, assembly_id=id) + def state_dict(self, backbone_only=False): """This state dict is optimized for storage, so it turns things to fp16 whenever possible. Note that we also only support int32 residue indices, I'm hoping we don't @@ -308,6 +394,11 @@ def state_dict(self, backbone_only=False): elif isinstance(v, ProteinComplexMetadata): dct[k] = asdict(v) dct["atom37_positions"] = dct["atom37_positions"][dct["atom37_mask"]] + dct["metadata"]["mmcif"] = None + # These can be populated with non-serializable objects and are not needed for reconstruction + dct.pop("atoms", None) + dct.pop("atom_mask", None) + dct.pop("per_chain_kd_trees", None) return dct def to_blob(self, backbone_only=False) -> bytes: @@ -322,6 +413,10 @@ def from_state_dict(cls, dct): k: (v.astype(np.float32) if k in ["atom37_positions", "confidence"] else v) for k, v in dct.items() } + if "chain_boundaries" in dct: + del dct["chain_boundaries"] + if "chain_boundaries" in dct["metadata"]: + del dct["metadata"]["chain_boundaries"] dct["metadata"] = ProteinComplexMetadata(**dct["metadata"]) return cls(**dct) @@ -342,13 +437,45 @@ def from_blob(cls, input: Path | str | io.BytesIO | bytes): ) @classmethod - def from_chains(cls, chains: Sequence[ProteinChain]): + def from_rcsb(cls, pdb_id: str, keep_source: bool = False) -> ProteinComplex: + f: io.StringIO = rcsb.fetch(pdb_id, "cif") # type: ignore + return cls.from_mmcif(f, id=pdb_id, keep_source=keep_source, is_predicted=False) + + @classmethod + def from_mmcif( + cls, + path: PathOrBuffer, + id: str | None = None, + assembly_id: str | None = None, + is_predicted: bool = False, + keep_source: bool = False, + ): + """Return a ProteinComplex object from an mmcif file. + TODO(@zeming): there's actually multiple complexes per file, but for ease of implementation, + we only consider the first defined complex! + + Args: + path (str | Path | io.TextIO): Path or buffer to read mmcif file from. Should be uncompressed. + id (str, optional): String identifier to assign to structure. Will attempt to infer otherwise. + is_predicted (bool): If True, reads b factor as the confidence readout. Default: False. + chain_id (str, optional): Select a chain corresponding to (author) chain id. + """ + mmcif = MmcifWrapper.read(path, id) + return get_assembly_fast(mmcif, assembly_id=assembly_id) + + @classmethod + def from_chains( + cls, + chains: Sequence[ProteinChain], + mmcif: MmcifWrapper | None = None, + all_assembly_metadata_dictionary: dict[str, list[str]] | None = None, + ): if not chains: raise ValueError( "Cannot create a ProteinComplex from an empty list of chains" ) - # TODO: Make a proper protein complex class + # TODO(roshan): Make a proper protein complex class def join_arrays(arrays: Sequence[np.ndarray], sep: np.ndarray): full_array = [] for array in arrays: @@ -376,7 +503,6 @@ def join_arrays(arrays: Sequence[np.ndarray], sep: np.ndarray): ent2num_max = -1 ent2num = {} total_index = 0 - chain_boundaries = [] for i, c in enumerate(chains): num_res = c.residue_index.shape[0] if c.chain_id not in chain2num: @@ -401,7 +527,6 @@ def join_arrays(arrays: Sequence[np.ndarray], sep: np.ndarray): } ) - chain_boundaries.append((total_index, total_index + num_res)) total_index += num_res + 1 sep = np.array([-1]) @@ -412,20 +537,25 @@ def join_arrays(arrays: Sequence[np.ndarray], sep: np.ndarray): array_args.update(update) metadata = ProteinComplexMetadata( - chain_boundaries=chain_boundaries, + mmcif=mmcif, chain_lookup={v: k for k, v in chain2num.items()}, entity_lookup={v: k for k, v in ent2num.items()}, + assembly_composition=all_assembly_metadata_dictionary, ) return cls( id=chains[0].id, - sequence=esm3_c.CHAIN_BREAK_STR.join(chain.sequence for chain in chains), + sequence=residue_constants.CHAIN_BREAK_TOKEN.join( + chain.sequence for chain in chains + ), metadata=metadata, **array_args, ) def infer_oxygen(self) -> ProteinComplex: """Oxygen position is fixed given N, CA, C atoms. Infer it if not provided.""" + O_missing_indices = np.argwhere(np.isnan(self.atoms["O"]).any(axis=1)).squeeze() + O_vector = torch.tensor([0.6240, -1.0613, 0.0103], dtype=torch.float32) N, CA, C = torch.from_numpy(self.atoms[["N", "CA", "C"]]).float().unbind(dim=1) N = torch.roll(N, -3) @@ -437,15 +567,56 @@ def infer_oxygen(self) -> ProteinComplex: atom37_positions = self.atom37_positions.copy() atom37_mask = self.atom37_mask.copy() - atom37_positions[:, residue_constants.atom_order["O"]] = O.numpy() - atom37_mask[:, residue_constants.atom_order["O"]] = ~np.isnan( - atom37_positions[:, residue_constants.atom_order["O"]] + atom37_positions[O_missing_indices, residue_constants.atom_order["O"]] = O[ + O_missing_indices + ].numpy() + atom37_mask[O_missing_indices, residue_constants.atom_order["O"]] = ~np.isnan( + atom37_positions[O_missing_indices, residue_constants.atom_order["O"]] + ).any(-1) + new_chain = replace( + self, atom37_positions=atom37_positions, atom37_mask=atom37_mask + ) + return new_chain + + def infer_cbeta(self, infer_cbeta_for_glycine: bool = False) -> ProteinComplex: + """Return a new chain with inferred CB atoms at all residues except GLY. + + Args: + infer_cbeta_for_glycine (bool): If True, infers a beta carbon for glycine + residues, even though that residue doesn't have one. Default off. + + NOTE(rverkuil): The reason for having this switch in the first place + is that sometimes we want a (inferred) CB coordinate for every residue, + for example for making a pairwise distance matrix, or doing an RMSD + calculation between two designs for a given structural template, w/ + CB atoms. + """ + atom37_positions = self.atom37_positions.copy() + atom37_mask = self.atom37_mask.copy() + + N, CA, C = np.moveaxis(self.atoms[["N", "CA", "C"]], 1, 0) + # See usage in trDesign codebase. + # https://github.com/gjoni/trDesign/blob/f2d5930b472e77bfacc2f437b3966e7a708a8d37/02-GD/utils.py#L140 + inferred_cbeta_positions = infer_CB(C, N, CA, 1.522, 1.927, -2.143) + if not infer_cbeta_for_glycine: + inferred_cbeta_positions[np.array(list(self.sequence)) == "G", :] = np.nan + + atom37_positions[:, residue_constants.atom_order["CB"]] = ( + inferred_cbeta_positions + ) + atom37_mask[:, residue_constants.atom_order["CB"]] = ~np.isnan( + atom37_positions[:, residue_constants.atom_order["CB"]] ).any(-1) new_chain = replace( self, atom37_positions=atom37_positions, atom37_mask=atom37_mask ) return new_chain + @classmethod + def from_open_source(cls, pc: ProteinComplex): + # TODO(@zeming): deprecated, should delete + return pc + @classmethod def concat(cls, objs: list[ProteinComplex]) -> ProteinComplex: pdb_ids = [obj.id for obj in objs] @@ -463,6 +634,50 @@ def _sanity_check_complexes_are_comparable(self, other: ProteinComplex): list(other.chain_iter()) ), "Protein complexes must have the same number of chains" + def rmsd( + self, + target: ProteinComplex, + also_check_reflection: bool = False, + mobile_inds: list[int] | np.ndarray | None = None, + target_inds: list[int] | np.ndarray | None = None, + only_compute_backbone_rmsd: bool = False, + compute_chain_assignment: bool = True, + ): + """ + Compute the RMSD between this protein chain and another. + + Args: + target (ProteinComplex): The target (other) protein complex to compare to. + also_check_reflection (bool, optional): If True, also check if the reflection of the mobile atoms has a lower RMSD. + mobile_inds (list[int], optional): The indices of the mobile atoms to align. These are NOT residue indices + target_inds (list[int], optional): The indices of the target atoms to align. These are NOT residue indices + only_compute_backbone_rmsd (bool, optional): If True, only compute the RMSD of the backbone atoms. + """ + if compute_chain_assignment: + aligned = self.dockq(target).aligned + else: + aligned = self + + aligner = Aligner( + aligned if mobile_inds is None else aligned[mobile_inds], + target if target_inds is None else target[target_inds], + only_compute_backbone_rmsd, + ) + avg_rmsd = aligner.rmsd + + if not also_check_reflection: + return avg_rmsd + + aligner = Aligner( + aligned if mobile_inds is None else aligned[mobile_inds], + target if target_inds is None else target[target_inds], + only_compute_backbone_rmsd, + use_reflection=True, + ) + avg_rmsd_neg = aligner.rmsd + + return min(avg_rmsd, avg_rmsd_neg) + def lddt_ca( self, target: ProteinComplex, @@ -537,6 +752,10 @@ def dockq(self, native: ProteinComplex): # This function uses dockqv2 to compute the DockQ score. Because it does a mapping # over all possible chains, it's quite slow. Be careful not to use this in an inference loop # or something that requires fast scoring. It defaults to 8 CPUs. + # + # TODO(@zeming): Because we haven't properly implemented protein complexes for mmcif, + # if your protein has multi-letter or repeated chain IDs, this will fail. Please call + # pc = pc.normalize_chain_ids_for_pdb() before calling this function in that case (limit is 62 chains) try: pass @@ -658,3 +877,316 @@ def parse_dict(d: dict[str, Any]) -> DockQSingleScore: ) return result + + @cached_property + def per_chain_kd_trees(self): + # Iterate over chains, build KDTree for each chain + kdtrees = [] + + CA = self.atoms["CA"] + + for start, end in self.chain_boundaries: + chain_CA = CA[start:end] + chain_CA = chain_CA[np.isfinite(chain_CA).all(axis=-1)] + kdtrees.append(KDTree(chain_CA)) + + return kdtrees + + def chain_adjacency(self, cutoff: float = 8.0) -> np.ndarray: + # Compute adjacency matrix for protein complex + num_chains = self.num_chains + adjacency = np.zeros((num_chains, num_chains), dtype=bool) + for (i, kdtree), (j, kdtree2) in itertools.combinations( + enumerate(self.per_chain_kd_trees), 2 + ): + adj = kdtree.query_ball_tree(kdtree2, cutoff) + any_is_adjacent = any(len(a) > 0 for a in adj) + adjacency[i, j] = any_is_adjacent + adjacency[j, i] = any_is_adjacent + return adjacency + + def chain_adjacency_by_index(self, index: int, cutoff: float = 8.0) -> np.ndarray: + num_chains = len(self.chain_boundaries) + adjacency = np.zeros(num_chains, dtype=bool) + for i, kdtree in enumerate(self.per_chain_kd_trees): + if i == index: + continue + adj = kdtree.query_ball_tree(self.per_chain_kd_trees[index], cutoff) + adjacency[i] = any(len(a) > 0 for a in adj) + return adjacency + + def add_prefix_to_chain_ids(self, prefix: str) -> ProteinComplex: + """Rename all chains in the complex with a given prefix. + + Args: + prefix (str): The prefix to use for the new chain IDs. Each chain will be + named as "{prefix}_{chain_id}". + + Returns: + ProteinComplex: A new protein complex with renamed chains. + """ + new_chains = [] + for chain in self.chain_iter(): + # Create new chain with updated chain_id + new_chain = replace(chain, chain_id=f"{prefix}_{chain.chain_id}") + new_chains.append(new_chain) + return ProteinComplex.from_chains(new_chains) + + def sasa(self, by_residue: bool = True): + chain = self.as_chain(force_conversion=True) + return chain.sasa(by_residue=by_residue) + + def to_mmcif_string(self) -> str: + """Convert the ProteinComplex to mmCIF format. + + Returns: + str: The mmCIF content as a string. + """ + # Convert the ProteinComplex to a biotite AtomArray + # Collect all atoms from all chains + all_atoms = [] + for chain in self.chain_iter(): + chain_atom_array = chain.atom_array + # Convert AtomArray to list of atoms and add to collection + all_atoms.extend(chain_atom_array) + + # Create combined AtomArray from all atoms + if not all_atoms: + raise ValueError("No atoms found in protein complex") + + atom_array = bs.array(all_atoms) + + # Create CIF file + f = CIFFile() + set_structure_pdbx(f, atom_array, data_block=self.id) + + # Add entity information for proper mmCIF structure + self._add_entity_information(f) + + # Write to string + output = io.StringIO() + f.write(output) + return output.getvalue() + + def _add_entity_information(self, cif_file: CIFFile) -> None: + """Add entity, entity_poly, and struct_asym sections to CIF file.""" + + # Group chains by sequence to create unique entities + entity_map = {} # sequence -> entity_id + chain_to_entity = {} # chain_id -> entity_id + entity_sequences = {} # entity_id -> sequence + entity_id_counter = 1 + + for chain in self.chain_iter(): + sequence = chain.sequence + if sequence not in entity_map: + entity_map[sequence] = entity_id_counter + entity_sequences[entity_id_counter] = sequence + entity_id_counter += 1 + chain_to_entity[chain.chain_id] = entity_map[sequence] + + # Create _entity section + entity_ids = [] + entity_types = [] + entity_descriptions = [] + + for entity_id in sorted(entity_sequences.keys()): + entity_ids.append(str(entity_id)) + entity_types.append("polymer") + entity_descriptions.append(f"Protein chain (entity {entity_id})") + + cif_file.block["entity"] = CIFCategory( + name="entity", + columns={ + "id": CIFColumn( + data=CIFData(array=np.array(entity_ids), dtype=np.str_) + ), + "type": CIFColumn( + data=CIFData(array=np.array(entity_types), dtype=np.str_) + ), + "pdbx_description": CIFColumn( + data=CIFData(array=np.array(entity_descriptions), dtype=np.str_) + ), + }, + ) + + # Create _entity_poly section + poly_entity_ids = [] + poly_types = [] + poly_nstd_linkages = [] + poly_sequences = [] + + for entity_id in sorted(entity_sequences.keys()): + poly_entity_ids.append(str(entity_id)) + poly_types.append("polypeptide(L)") + poly_nstd_linkages.append("no") + poly_sequences.append(entity_sequences[entity_id]) + + cif_file.block["entity_poly"] = CIFCategory( + name="entity_poly", + columns={ + "entity_id": CIFColumn( + data=CIFData(array=np.array(poly_entity_ids), dtype=np.str_) + ), + "type": CIFColumn( + data=CIFData(array=np.array(poly_types), dtype=np.str_) + ), + "nstd_linkage": CIFColumn( + data=CIFData(array=np.array(poly_nstd_linkages), dtype=np.str_) + ), + "pdbx_seq_one_letter_code": CIFColumn( + data=CIFData(array=np.array(poly_sequences), dtype=np.str_) + ), + }, + ) + + # Create _struct_asym section + asym_ids = [] + asym_entity_ids = [] + asym_details = [] + + for chain in self.chain_iter(): + asym_ids.append(chain.chain_id) + asym_entity_ids.append(str(chain_to_entity[chain.chain_id])) + asym_details.append("") + + cif_file.block["struct_asym"] = CIFCategory( + name="struct_asym", + columns={ + "id": CIFColumn(data=CIFData(array=np.array(asym_ids), dtype=np.str_)), + "entity_id": CIFColumn( + data=CIFData(array=np.array(asym_entity_ids), dtype=np.str_) + ), + "details": CIFColumn( + data=CIFData(array=np.array(asym_details), dtype=np.str_) + ), + }, + ) + + +def get_assembly_fast( + mmcif: MmcifWrapper, + assembly_id=None, + model=None, + data_block=None, + altloc="first", + use_author_fields=True, +): + pdbx_file = mmcif.raw + if pdbx_file is None: + raise InvalidFileError("No mmCIF data loaded") + assembly_gen_category = pdbx_file.block["pdbx_struct_assembly_gen"] + if assembly_gen_category is None: + raise InvalidFileError("File has no 'pdbx_struct_assembly_gen' category") + + struct_oper_category = pdbx_file.block["pdbx_struct_oper_list"] + if struct_oper_category is None: + raise InvalidFileError("File has no 'pdbx_struct_oper_list' category") + + if assembly_id is None: + assembly_id = assembly_gen_category["assembly_id"].data.array[0] + elif assembly_id not in assembly_gen_category["assembly_id"].data.array: + raise KeyError(f"File has no Assembly ID '{assembly_id}'") + + ### Calculate all possible transformations + transformations = _get_transformations(struct_oper_category) + + ### Get structure according to additional parameters + structure = get_structure( + pdbx_file, model, data_block, altloc, ["label_asym_id"], use_author_fields + )[0] # type: ignore + # TODO(@zeming) This line will remove all non-protein structural elements, + # we should remove this when we want to parse these too. + structure: bs.AtomArray = structure[ + bs.filter_amino_acids(structure) & ~structure.hetero # type: ignore + ] + if len(structure) == 0: + raise NoProteinError + unique_asym_ids = np.unique(structure.label_asym_id) # type: ignore + asym2chain = {} + asym2auth = {} + for asym_id in unique_asym_ids: + sub_structure: bs.AtomArray = structure[structure.label_asym_id == asym_id] # type: ignore + chain_id: str = sub_structure[0].chain_id # type: ignore + ( + sequence, + atom_positions, + atom_mask, + residue_index, + insertion_code, + confidence, + entity_id, + ) = chain_to_ndarray(sub_structure, mmcif, chain_id, False) + + asym2chain[asym_id] = ProteinChain( + id=mmcif.id or "unknown", + sequence=sequence, + chain_id=chain_id, + entity_id=entity_id, + atom37_positions=atom_positions, + atom37_mask=atom_mask, + residue_index=residue_index, + insertion_code=insertion_code, + confidence=confidence, + mmcif=None, + ) + asym2auth[asym_id] = chain_id + + ### Get transformations and apply them to the affected asym IDs + assembly = [] + assembly_id_dict: dict[str, list[str]] = {} + + # Process the target assembly ID + for aid, op_expr, asym_id_expr in zip( + assembly_gen_category["assembly_id"].data.array, + assembly_gen_category["oper_expression"].data.array, + assembly_gen_category["asym_id_list"].data.array, + ): + if aid == assembly_id: + # Parse operations and asym IDs for this specific entry + operations = _parse_operation_expression(op_expr) + asym_ids = asym_id_expr.split(",") + + # Filter affected asym IDs to only protein chains, preserving order + sub_structures = [ + asym2chain[asym_id] for asym_id in asym_ids if asym_id in asym2chain + ] + + # Apply transformations + sub_assembly = _apply_transformations_fast( + sub_structures, transformations, operations + ) + assembly.extend(sub_assembly) + + # Build assembly_id_dict for this entry + assembly_id_dict[aid] = assembly_id_dict.get(aid, []) + [ + asym2auth[id_] for id_ in asym_ids if id_ in asym2auth + ] + + if len(assembly) == 0: + raise NoProteinError + return ProteinComplex.from_chains(assembly, mmcif, assembly_id_dict) + + +def protein_chain_to_protein_complex(chain: ProteinChain) -> ProteinComplex: + if "|" not in chain.sequence: + return ProteinComplex.from_chains([chain]) + chain_breaks = np.array(list(chain.sequence)) == "|" + chain_break_inds = np.where(chain_breaks)[0] + chain_break_inds = np.concatenate([[0], chain_break_inds, [len(chain)]]) + chain_break_inds = np.array(list(zip(chain_break_inds[:-1], chain_break_inds[1:]))) + complex_chains = [] + for start, end in chain_break_inds: + if start != 0: + start += 1 + complex_chains.append(chain[start:end]) + complex_chains = [ + ProteinChain.from_atom37( + chain.atom37_positions, + sequence=chain.sequence, + chain_id=SINGLE_LETTER_CHAIN_IDS[i], + entity_id=i, + ) + for i, chain in enumerate(complex_chains) + ] + return ProteinComplex.from_chains(complex_chains) diff --git a/esm/utils/structure/protein_structure.py b/esm/utils/structure/protein_structure.py index 7f213eaa..cb91d110 100644 --- a/esm/utils/structure/protein_structure.py +++ b/esm/utils/structure/protein_structure.py @@ -194,7 +194,7 @@ def compute_rmsd_no_alignment( mean_squared_error = diff.square().view(diff.size(0), -1, 9).mean(dim=-1) else: mean_squared_error = diff.square().sum(dim=(1, 2)) / ( - num_valid_atoms.squeeze(-1) * 3 + num_valid_atoms.squeeze(-1) ) rmsd = torch.sqrt(mean_squared_error) diff --git a/esm/widgets/components/function_annotator.py b/esm/widgets/components/function_annotator.py index 714238f9..f567f94d 100644 --- a/esm/widgets/components/function_annotator.py +++ b/esm/widgets/components/function_annotator.py @@ -4,9 +4,7 @@ from ipywidgets import widgets from esm.sdk.api import FunctionAnnotation -from esm.tokenization.function_tokenizer import ( - InterProQuantizedTokenizer, -) +from esm.tokenization.function_tokenizer import InterProQuantizedTokenizer TRIE: pygtrie.CharTrie | None = None diff --git a/esm/widgets/components/results_visualizer.py b/esm/widgets/components/results_visualizer.py index 99692e51..261c0a5d 100644 --- a/esm/widgets/components/results_visualizer.py +++ b/esm/widgets/components/results_visualizer.py @@ -7,15 +7,11 @@ import matplotlib.pyplot as plt from esm.sdk.api import ESMProtein -from esm.widgets.utils.drawing.draw_category_array import ( - draw_data_array, -) +from esm.widgets.utils.drawing.draw_category_array import draw_data_array from esm.widgets.utils.drawing.draw_function_annotations import ( draw_function_annotations, ) -from esm.widgets.utils.drawing.draw_protein_structure import ( - draw_protein_structure, -) +from esm.widgets.utils.drawing.draw_protein_structure import draw_protein_structure from esm.widgets.utils.serialization import ( create_download_button_from_buffer, protein_to_pdb_buffer, diff --git a/esm/widgets/components/sasa_prompt_selector.py b/esm/widgets/components/sasa_prompt_selector.py index ecc5c1b4..9c026500 100644 --- a/esm/widgets/components/sasa_prompt_selector.py +++ b/esm/widgets/components/sasa_prompt_selector.py @@ -3,16 +3,9 @@ import ipywidgets as widgets from esm.utils.structure.protein_chain import ProteinChain -from esm.widgets.utils.drawing.colors import ( - hex_to_rgba_tuple, - rgba_tuple_to_hex, -) -from esm.widgets.utils.drawing.draw_category_array import ( - draw_data_array, -) -from esm.widgets.utils.parsing import ( - convert_range_string_to_list_of_ranges, -) +from esm.widgets.utils.drawing.colors import hex_to_rgba_tuple, rgba_tuple_to_hex +from esm.widgets.utils.drawing.draw_category_array import draw_data_array +from esm.widgets.utils.parsing import convert_range_string_to_list_of_ranges from esm.widgets.utils.prompting import PromptManager diff --git a/esm/widgets/components/secondary_structure_prompt_selector.py b/esm/widgets/components/secondary_structure_prompt_selector.py index 020180fe..b8007d69 100644 --- a/esm/widgets/components/secondary_structure_prompt_selector.py +++ b/esm/widgets/components/secondary_structure_prompt_selector.py @@ -4,16 +4,9 @@ import pydssp from esm.utils.structure.protein_chain import ProteinChain -from esm.widgets.utils.drawing.colors import ( - hex_to_rgba_tuple, - rgba_tuple_to_hex, -) -from esm.widgets.utils.drawing.draw_category_array import ( - draw_data_array, -) -from esm.widgets.utils.parsing import ( - convert_range_string_to_list_of_ranges, -) +from esm.widgets.utils.drawing.colors import hex_to_rgba_tuple, rgba_tuple_to_hex +from esm.widgets.utils.drawing.draw_category_array import draw_data_array +from esm.widgets.utils.parsing import convert_range_string_to_list_of_ranges from esm.widgets.utils.prompting import PromptManager diff --git a/esm/widgets/components/sequence_prompt_selector.py b/esm/widgets/components/sequence_prompt_selector.py index d538e670..c5e3526f 100644 --- a/esm/widgets/components/sequence_prompt_selector.py +++ b/esm/widgets/components/sequence_prompt_selector.py @@ -6,9 +6,7 @@ hex_to_rgba_tuple, rgba_tuple_to_rgba_html_string, ) -from esm.widgets.utils.parsing import ( - convert_range_string_to_list_of_ranges, -) +from esm.widgets.utils.parsing import convert_range_string_to_list_of_ranges from esm.widgets.utils.prompting import PromptManager diff --git a/esm/widgets/components/structure_prompt_selector.py b/esm/widgets/components/structure_prompt_selector.py index f4b497c0..13a9df78 100644 --- a/esm/widgets/components/structure_prompt_selector.py +++ b/esm/widgets/components/structure_prompt_selector.py @@ -10,12 +10,8 @@ from esm.utils.structure.protein_chain import ProteinChain from esm.widgets.utils import indexing -from esm.widgets.utils.drawing.draw_protein_structure import ( - draw_protein_structure, -) -from esm.widgets.utils.parsing import ( - convert_range_string_to_list_of_ranges, -) +from esm.widgets.utils.drawing.draw_protein_structure import draw_protein_structure +from esm.widgets.utils.parsing import convert_range_string_to_list_of_ranges from esm.widgets.utils.printing import wrapped_print from esm.widgets.utils.prompting import PromptManager diff --git a/esm/widgets/utils/drawing/draw_function_annotations.py b/esm/widgets/utils/drawing/draw_function_annotations.py index c71e5434..59e9f7cf 100644 --- a/esm/widgets/utils/drawing/draw_function_annotations.py +++ b/esm/widgets/utils/drawing/draw_function_annotations.py @@ -9,10 +9,7 @@ from PIL import Image from esm.sdk.api import FunctionAnnotation -from esm.utils.function.interpro import ( - InterPro, - InterProEntryType, -) +from esm.utils.function.interpro import InterPro, InterProEntryType @contextmanager diff --git a/esm/widgets/utils/prompting.py b/esm/widgets/utils/prompting.py index 1ce6d9c6..1e89bb64 100644 --- a/esm/widgets/utils/prompting.py +++ b/esm/widgets/utils/prompting.py @@ -9,9 +9,7 @@ from esm.utils import encoding from esm.widgets.utils import indexing from esm.widgets.utils.drawing.colors import rgba_tuple_to_hex -from esm.widgets.utils.drawing.draw_category_array import ( - draw_data_array, -) +from esm.widgets.utils.drawing.draw_category_array import draw_data_array from esm.widgets.utils.printing import wrapped_print diff --git a/esm/widgets/views/esm3_generation_launcher.py b/esm/widgets/views/esm3_generation_launcher.py index e94c60ff..f8bf8f3b 100644 --- a/esm/widgets/views/esm3_generation_launcher.py +++ b/esm/widgets/views/esm3_generation_launcher.py @@ -13,13 +13,9 @@ GenerationConfig, ) from esm.utils.constants import models -from esm.widgets.components.results_visualizer import ( - create_results_visualizer, -) +from esm.widgets.components.results_visualizer import create_results_visualizer from esm.widgets.utils.printing import wrapped_print -from esm.widgets.utils.serialization import ( - create_download_results_button, -) +from esm.widgets.utils.serialization import create_download_results_button def create_esm3_generation_launcher( diff --git a/esm/widgets/views/esm3_prompt_selector.py b/esm/widgets/views/esm3_prompt_selector.py index 035db28e..f7e60686 100644 --- a/esm/widgets/views/esm3_prompt_selector.py +++ b/esm/widgets/views/esm3_prompt_selector.py @@ -1,8 +1,6 @@ from ipywidgets import widgets -from esm.widgets.components.sasa_prompt_selector import ( - create_sasa_prompt_selector, -) +from esm.widgets.components.sasa_prompt_selector import create_sasa_prompt_selector from esm.widgets.components.secondary_structure_prompt_selector import ( create_secondary_structure_prompt_selector, ) diff --git a/esm/widgets/views/generation.py b/esm/widgets/views/generation.py index 19015f60..fdec2094 100644 --- a/esm/widgets/views/generation.py +++ b/esm/widgets/views/generation.py @@ -4,20 +4,12 @@ from esm.sdk.api import ESM3InferenceClient, ESMProtein from esm.utils.constants import esm3 as C -from esm.widgets.components.function_annotator import ( - create_function_annotator, -) +from esm.widgets.components.function_annotator import create_function_annotator from esm.widgets.utils.prompting import PromptManagerCollection from esm.widgets.utils.protein_import import ProteinImporter -from esm.widgets.views.esm3_generation_launcher import ( - create_esm3_generation_launcher, -) -from esm.widgets.views.esm3_prompt_preview import ( - create_esm3_prompt_preview, -) -from esm.widgets.views.esm3_prompt_selector import ( - create_esm3_prompt_selector, -) +from esm.widgets.views.esm3_generation_launcher import create_esm3_generation_launcher +from esm.widgets.views.esm3_prompt_preview import create_esm3_prompt_preview +from esm.widgets.views.esm3_prompt_selector import create_esm3_prompt_selector def create_generation_ui( diff --git a/esm/widgets/views/inverse_folding.py b/esm/widgets/views/inverse_folding.py index 8becb8eb..50d9a128 100644 --- a/esm/widgets/views/inverse_folding.py +++ b/esm/widgets/views/inverse_folding.py @@ -6,9 +6,7 @@ ESMProteinError, GenerationConfig, ) -from esm.widgets.components.results_visualizer import ( - create_results_visualizer, -) +from esm.widgets.components.results_visualizer import create_results_visualizer from esm.widgets.utils.printing import wrapped_print from esm.widgets.utils.protein_import import ProteinImporter diff --git a/esm/widgets/views/login.py b/esm/widgets/views/login.py index 2d8be5a3..5c7b6706 100644 --- a/esm/widgets/views/login.py +++ b/esm/widgets/views/login.py @@ -4,10 +4,7 @@ from ipywidgets import widgets -from esm.widgets.utils.clients import ( - get_forge_client, - get_local_client, -) +from esm.widgets.utils.clients import get_forge_client, get_local_client from esm.widgets.utils.types import ClientInitContainer diff --git a/esm/widgets/views/prediction.py b/esm/widgets/views/prediction.py index de6666d2..94ff49dc 100644 --- a/esm/widgets/views/prediction.py +++ b/esm/widgets/views/prediction.py @@ -6,9 +6,7 @@ ESMProteinError, GenerationConfig, ) -from esm.widgets.components.results_visualizer import ( - create_results_visualizer, -) +from esm.widgets.components.results_visualizer import create_results_visualizer from esm.widgets.utils.printing import wrapped_print from esm.widgets.utils.protein_import import ProteinImporter diff --git a/pixi.lock b/pixi.lock index 59428ae4..c392edf5 100644 --- a/pixi.lock +++ b/pixi.lock @@ -12,6 +12,8 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_5.conda - conda: https://conda.anaconda.org/conda-forge/noarch/backports.tarfile-1.2.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.1.0-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py312h2ec8cdc_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.4-hb9d3cd8_0.conda @@ -21,12 +23,16 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cmake-4.0.0-h74e3db0_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cmarkgfm-2024.11.20-py312h66e93f0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.3-py312hd9148b4_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.9-py312hd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/cryptography-44.0.2-py312hda17c39_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.7.0-h5888daf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.18.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.59.0-py312h8a5da7c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/freetype-2.13.3-ha770c72_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.2.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda @@ -40,11 +46,15 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/jeepney-0.9.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/keyring-25.6.0-pyha804496_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.8-py312h68727a3_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.17-h717163a_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_4.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h0aef613_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-31_h59b9bed_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.1.0-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.1.0-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-31_he106b2a_openblas.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.13.0-h332b0f4_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.23-h86f0d12_0.conda @@ -80,8 +90,10 @@ environments: - 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-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-3.0.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.5-py312he3d6523_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nh3-0.2.21-py39h77e2912_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.3.2-py312h33ff503_0.conda @@ -96,6 +108,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.3-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.9-h9e4cc4f_1_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda @@ -104,6 +117,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.12-6_cp312.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.2-py312h178313f_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8c095d6_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/readme_renderer-44.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.3-pyhd8ed1ab_1.conda @@ -119,6 +133,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/twine-6.1.0-pyh29332c3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.13.0-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-16.0.0-py312h66e93f0_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.3.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.45.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb9d3cd8_0.conda @@ -133,10 +148,15 @@ environments: - pypi: https://files.pythonhosted.org/packages/b4/0d/b7a0f10f5100dcf51ae36ba31490169bfa45617323bd82af43e1fb0098fb/biopython-1.85-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/3e/04/3f09ba937cdd5381743ffabd48c18d790a684a11fb6b23dfd8d30f0ec858/biotite-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/80/cd/c607b6337ddcf55cc0249527819b727ef28481d7c56ace54cca69400c2b9/biotraj-1.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/b6/6d/79fad38fcd7e1fc6961061b46cc87706c5c946088bc4620abf0d0aa49420/boto3-1.40.9-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/02/e9/367e81e114deb92a6e0d5740f0bff4548af710be318af65265b9aad72237/botocore-1.40.9-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e8/0f/b1a9b09a84ef98b9fc38d50c6b2815cb2256b804a78e7d838ddfbdc035c7/cloudpathlib-0.21.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/52/f2/9e726e4489f947557290605e3ee33b6ba09fe5dac9213263e0ada75200cf/dna_features_viewer-3.1.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/87/62/9773de14fe6c45c23649e98b83231fffd7b9892b6cf863251dc2afa73643/einops-0.8.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl + - pypi: direct+https://github.com/Dao-AILab/flash-attention/releases/download/v2.8.1/flash_attn-2.8.1+cu12torch2.7cxx11abiFALSE-cp312-cp312-linux_x86_64.whl - pypi: https://files.pythonhosted.org/packages/44/4b/e0cfc1a6f17e990f3e64b7d941ddc4acdc7b19d6edd51abf495f32b1a9e4/fsspec-2025.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl @@ -144,9 +164,12 @@ environments: - pypi: https://files.pythonhosted.org/packages/99/e3/2232d0e726d4d6ea69643b9593d97d0e7e6ea69c2fe9ed5de34d476c1c47/huggingface_hub-0.30.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/20/3a/917cb9e72f4e1a4ea13c862533205ae1319bd664119189ee5cc9e4e95ebf/ipython-9.0.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/58/6a/9166369a2f092bd286d24e6307de555d63616e8ddb373ebad2b5635ca4cd/ipywidgets-8.1.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/91/29/df4b9b42f2be0b623cbd5e2140cafcaa2bef0759a00b7b70104dcfe2fb51/joblib-1.4.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/43/6a/ca128561b22b60bd5a0c4ea26649e68c8556b82bc70a0c396eebc977fe86/jupyterlab_widgets-3.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl @@ -171,7 +194,11 @@ environments: - pypi: https://files.pythonhosted.org/packages/e4/ea/d836f008d33151c7a1f62caf3d8dd782e4d15f6a43897f64480c2b8de2ad/prompt_toolkit-3.0.50-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a3/17/c476487ba903c7d793db633b4e8ca4a420ae272890302189d9402ba8ff85/py3dmol-2.5.2-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/00/78/9cbcc1c073b9d4918e925af1a059762265dc65004e020511b2a06fbfd020/pydssp-0.9.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ec/cd/bd196b2cf014afb1009de8b0f05ecd54011d881944e62763f3c1b1e8ef37/pygtrie-2.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/6d/4f/d073e09df851cfa251ef7840007d04db3293a0482ce607d2b993926089be/s3transfer-0.13.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a6/f8/dae3421624fcc87a89d42e1898a798bc7ff72c61f38973a65d60df8f124c/safetensors-0.5.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/29/7a/8bce8968883e9465de20be15542f4c7e221952441727c4dad24d534c6d99/scikit_learn-1.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl @@ -188,8 +215,195 @@ environments: - pypi: https://files.pythonhosted.org/packages/7b/9f/92d3091c44cb19add044064af1bf1345cd35fbb84d32a3690f912800a295/transformers-4.48.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/06/00/59500052cb1cf8cf5316be93598946bc451f14072c6ff256904428eaf03c/triton-3.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ca/51/5447876806d1088a0f8f71e16542bf350918128d0a69437df26047c8e46f/widgetsnbextension-4.0.14-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/92/a7/5f4c6c2a62dd88f58133e333af1c251dd08f98d48445f650889d85e43b7b/zstd-1.5.6.7.tar.gz - pypi: ./ + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_5.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports.tarfile-1.2.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-1.1.0-h5505292_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-bin-1.1.0-h5505292_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.1.0-py312hd8f9ff3_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.5-h5505292_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.8.3-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2025.8.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-1.17.1-py312h0fad829_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmake-4.1.0-hae74ae4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmarkgfm-2024.11.20-py312hea69d52_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/contourpy-1.3.3-py312ha0dd364_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.11-py312hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.22-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.18.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/fonttools-4.59.0-py312h6daa0e5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/freetype-2.13.3-hce30654_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-75.1-hfee45f7_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/id-1.5.0-pyh29332c3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.10-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.7.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.4.0-pyhd8ed1ab_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.context-6.0.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.functools-4.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/keyring-25.6.0-pyh534df25_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/kiwisolver-1.4.9-py312hdc12c9d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.21.3-h237132a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lcms2-2.17-h7eeda09_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lerc-4.0.0-hd64df32_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.9.0-34_h10e41b3_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlicommon-1.1.0-h5505292_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlidec-1.1.0-h5505292_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlienc-1.1.0-h5505292_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.9.0-34_hb3479ef_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.14.1-h73640d1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-20.1.8-hf598326_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libdeflate-1.24-h5773f1b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libev-4.33-h93a5062_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.7.1-hec049ff_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.6-h1da3d7d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libfreetype-2.13.3-hce30654_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libfreetype6-2.13.3-h1d14073_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.1.0-hfdf1602_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.1.0-hb74de2c_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libglib-2.84.3-h587fa63_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.18-h23cfdf5_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libintl-0.25.1-h493aca8_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libjpeg-turbo-3.1.0-h5505292_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.9.0-34_hc9a63f6_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.1-h39f12f2_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.64.0-h6d7220d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.30-openmp_h60d53f8_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libpng-1.6.50-h280e0eb_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.50.4-h4237e3c_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libtiff-4.7.0-h025e3ab_6.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.51.0-h6caf38d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libwebp-base-1.6.0-h07db88b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxcb-1.17.0-hdb1d25a_0.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/llvm-openmp-20.1.8-hbb9b287_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/matplotlib-base-3.10.5-py312h05635fa_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.7.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nh3-0.3.0-py39h24c5d98_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.3.2-py312h2f38b44_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.3-h889cd5d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.5.2-he92f556_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-2.3.1-py312h98f7732_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pcre2-10.45-ha881caa_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pillow-11.3.0-py312h50aef2c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pkg-config-0.29.2-hde07d2e_1009.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pthread-stubs-0.4-hd74edd7_1002.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.3-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.11-hc22306f_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.11-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-8_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyyaml-6.0.2-py312h998013c_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/qhull-2020.2-h420ef59_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h1d1bf99_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/readme_renderer-44.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-1.0.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rfc3986-2.0.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/rhash-1.4.6-h5505292_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-14.1.0-pyhe01879c_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.16.1-py312h286a95b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h892fb3f_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/twine-6.1.0-pyh29332c3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.14.1-pyhe01879c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/unicodedata2-16.0.0-py312hea69d52_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.45.1-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xorg-libxau-1.0.12-h5505292_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xorg-libxdmcp-1.1.5-hd74edd7_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h925e9cb_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.23.0-py312hea69d52_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-h6491c7d_2.conda + - pypi: https://files.pythonhosted.org/packages/6f/12/e5e0282d673bb9746bacfb6e2dba8719989d3660cdb2ea79aee9a9651afb/anyio-4.10.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/54/5b/8b3b029c94c63ab4c1781d141615b4a837e658422381d460c5573d5d8262/biopython-1.85-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/21/e0/64716fb2ce9d7749bb41cc932c667b0f6d478e09367b36d273b1f77b06f3/biotite-1.4.0-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/c4/d2/369ed44ad23f8c0464f7b80d41143d717896097b39fe3dd3e07e6d162fef/biotraj-1.2.2-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/b6/6d/79fad38fcd7e1fc6961061b46cc87706c5c946088bc4620abf0d0aa49420/boto3-1.40.9-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/02/e9/367e81e114deb92a6e0d5740f0bff4548af710be318af65265b9aad72237/botocore-1.40.9-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/40/e7/6fea57b887f8e367c1e4a496ba03bfaf57824b766f777723ce1faf28834b/cloudpathlib-0.21.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/52/f2/9e726e4489f947557290605e3ee33b6ba09fe5dac9213263e0ada75200cf/dna_features_viewer-3.1.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/87/62/9773de14fe6c45c23649e98b83231fffd7b9892b6cf863251dc2afa73643/einops-0.8.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl + - pypi: direct+https://github.com/Dao-AILab/flash-attention/releases/download/v2.8.1/flash_attn-2.8.1+cu12torch2.7cxx11abiFALSE-cp312-cp312-linux_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/2f/e0/014d5d9d7a4564cf1c40b5039bc882db69fd881111e03ab3657ac0b218e2/fsspec-2025.7.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/51/a3/fa5897099454aa287022a34a30e68dbff0e617760f774f8bd1db17f06bd4/hf_xet-1.1.7-cp37-abi3-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/39/7b/bb06b061991107cd8783f300adff3e7b7f284e330fd82f507f2a1417b11d/huggingface_hub-0.34.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/63/f8/0031ee2b906a15a33d6bfc12dd09c3dfa966b3cb5b284ecfb7549e6ac3c4/ipython-9.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/58/6a/9166369a2f092bd286d24e6307de555d63616e8ddb373ebad2b5635ca4cd/ipywidgets-8.1.7-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7d/4f/1195bbac8e0c2acc5f740661631d8d750dc38d4a32b23ee5df3cde6f4e0d/joblib-1.5.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/43/6a/ca128561b22b60bd5a0c4ea26649e68c8556b82bc70a0c396eebc977fe86/jupyterlab_widgets-3.0.15-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ab/65/7d1de38c8a22cf8b1551469159d4b6cf49be2126adc2482de50976084d78/msgpack-1.1.1-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/9b/5d/f25ac7d4fb77cbd53ddc6d05d833c6bf52b12770a44fa9a447eed470ca9a/msgpack_numpy-0.4.8-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/eb/8d/776adee7bbf76365fdd7f2552710282c79a4ead5d2a46408c9043a2b70ba/networkx-3.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ce/4f/5249960887b1fbe561d9ff265496d170b55a735b76724f10ef19f9e40716/prompt_toolkit-3.0.51-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a3/17/c476487ba903c7d793db633b4e8ca4a420ae272890302189d9402ba8ff85/py3dmol-2.5.2-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/00/78/9cbcc1c073b9d4918e925af1a059762265dc65004e020511b2a06fbfd020/pydssp-0.9.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ec/cd/bd196b2cf014afb1009de8b0f05ecd54011d881944e62763f3c1b1e8ef37/pygtrie-2.5.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cd/70/69506d53397b4bd6954061bae75677ad34deb7f6ca3ba199660d6f728ff5/regex-2025.7.34-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/6d/4f/d073e09df851cfa251ef7840007d04db3293a0482ce607d2b993926089be/s3transfer-0.13.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8c/c9/bb114c158540ee17907ec470d01980957fdaf87b4aa07914c24eba87b9c6/safetensors-0.6.2-cp38-abi3-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/67/4e/899317092f5efcab0e9bc929e3391341cec8fb0e816c4789686770024580/scikit_learn-1.7.1-cp312-cp312-macosx_12_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8d/a6/28975479e35ddc751dc1ddc97b9b69bf7fcf074db31548aab37f8116674c/tokenizers-0.21.4-cp39-abi3-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/be/66/5c9a321b325aaecb92d4d1855421e3a055abd77903b7dab6575ca07796db/torch-2.8.0-cp312-none-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/8b/80/c78f88844e576c21580e64bd93de9df9bca223fef3e8195345680eb6f87f/torchtext-0.18.0-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/df/1d/0ea0b34bde92a86d42620f29baa6dcbb5c2fc85990316df5cb8f7abb8ea2/torchvision-0.23.0-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/9f/92d3091c44cb19add044064af1bf1345cd35fbb84d32a3690f912800a295/transformers-4.48.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ca/51/5447876806d1088a0f8f71e16542bf350918128d0a69437df26047c8e46f/widgetsnbextension-4.0.14-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/08/b8/2bc2590a34c733ea0570f366e6ad7d889d05c7825bd3ccab01f36ece71c6/zstd-1.5.7.2-cp312-cp312-macosx_11_0_arm64.whl + - pypi: ./ dev: channels: - url: https://conda.anaconda.org/conda-forge/ @@ -228,6 +442,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/double-conversion-3.3.1-h5888daf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.7.0-h5888daf_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.18.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 @@ -327,6 +542,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/nh3-0.2.21-py39h77e2912_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.9.1-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-22.13.0-hf235a45_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.3.2-py312h33ff503_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.3-h55fea9a_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.9-he970967_0.conda @@ -346,10 +562,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.3-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyright-1.1.399-py312h66e93f0_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.9.0-py312h91f0f75_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-8.4.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-6.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.9-h9e4cc4f_1_cpython.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.9-hd8ed1ab_1.conda @@ -410,6 +628,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.6-hb9d3cd8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.21.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py312h66e93f0_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda - pypi: https://files.pythonhosted.org/packages/6f/12/e5e0282d673bb9746bacfb6e2dba8719989d3660cdb2ea79aee9a9651afb/anyio-4.10.0-py3-none-any.whl @@ -418,10 +637,15 @@ environments: - pypi: https://files.pythonhosted.org/packages/b4/0d/b7a0f10f5100dcf51ae36ba31490169bfa45617323bd82af43e1fb0098fb/biopython-1.85-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/3e/04/3f09ba937cdd5381743ffabd48c18d790a684a11fb6b23dfd8d30f0ec858/biotite-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/80/cd/c607b6337ddcf55cc0249527819b727ef28481d7c56ace54cca69400c2b9/biotraj-1.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/b6/6d/79fad38fcd7e1fc6961061b46cc87706c5c946088bc4620abf0d0aa49420/boto3-1.40.9-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/02/e9/367e81e114deb92a6e0d5740f0bff4548af710be318af65265b9aad72237/botocore-1.40.9-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e8/0f/b1a9b09a84ef98b9fc38d50c6b2815cb2256b804a78e7d838ddfbdc035c7/cloudpathlib-0.21.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/52/f2/9e726e4489f947557290605e3ee33b6ba09fe5dac9213263e0ada75200cf/dna_features_viewer-3.1.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/87/62/9773de14fe6c45c23649e98b83231fffd7b9892b6cf863251dc2afa73643/einops-0.8.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl + - pypi: direct+https://github.com/Dao-AILab/flash-attention/releases/download/v2.8.1/flash_attn-2.8.1+cu12torch2.7cxx11abiFALSE-cp312-cp312-linux_x86_64.whl - pypi: https://files.pythonhosted.org/packages/44/4b/e0cfc1a6f17e990f3e64b7d941ddc4acdc7b19d6edd51abf495f32b1a9e4/fsspec-2025.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl @@ -429,9 +653,12 @@ environments: - pypi: https://files.pythonhosted.org/packages/99/e3/2232d0e726d4d6ea69643b9593d97d0e7e6ea69c2fe9ed5de34d476c1c47/huggingface_hub-0.30.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/20/3a/917cb9e72f4e1a4ea13c862533205ae1319bd664119189ee5cc9e4e95ebf/ipython-9.0.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/58/6a/9166369a2f092bd286d24e6307de555d63616e8ddb373ebad2b5635ca4cd/ipywidgets-8.1.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/91/29/df4b9b42f2be0b623cbd5e2140cafcaa2bef0759a00b7b70104dcfe2fb51/joblib-1.4.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/43/6a/ca128561b22b60bd5a0c4ea26649e68c8556b82bc70a0c396eebc977fe86/jupyterlab_widgets-3.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl @@ -456,7 +683,11 @@ environments: - pypi: https://files.pythonhosted.org/packages/e4/ea/d836f008d33151c7a1f62caf3d8dd782e4d15f6a43897f64480c2b8de2ad/prompt_toolkit-3.0.50-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a3/17/c476487ba903c7d793db633b4e8ca4a420ae272890302189d9402ba8ff85/py3dmol-2.5.2-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/00/78/9cbcc1c073b9d4918e925af1a059762265dc65004e020511b2a06fbfd020/pydssp-0.9.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ec/cd/bd196b2cf014afb1009de8b0f05ecd54011d881944e62763f3c1b1e8ef37/pygtrie-2.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/6d/4f/d073e09df851cfa251ef7840007d04db3293a0482ce607d2b993926089be/s3transfer-0.13.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a6/f8/dae3421624fcc87a89d42e1898a798bc7ff72c61f38973a65d60df8f124c/safetensors-0.5.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/29/7a/8bce8968883e9465de20be15542f4c7e221952441727c4dad24d534c6d99/scikit_learn-1.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl @@ -473,8 +704,222 @@ environments: - pypi: https://files.pythonhosted.org/packages/7b/9f/92d3091c44cb19add044064af1bf1345cd35fbb84d32a3690f912800a295/transformers-4.48.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/06/00/59500052cb1cf8cf5316be93598946bc451f14072c6ff256904428eaf03c/triton-3.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ca/51/5447876806d1088a0f8f71e16542bf350918128d0a69437df26047c8e46f/widgetsnbextension-4.0.14-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/92/a7/5f4c6c2a62dd88f58133e333af1c251dd08f98d48445f650889d85e43b7b/zstd-1.5.6.7.tar.gz - pypi: ./ + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_5.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports.tarfile-1.2.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-1.1.0-h5505292_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-bin-1.1.0-h5505292_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.1.0-py312hd8f9ff3_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.5-h5505292_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.8.3-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2025.8.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-1.17.1-py312h0fad829_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.3.1-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmake-4.1.0-hae74ae4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmarkgfm-2024.11.20-py312hea69d52_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/contourpy-1.3.3-py312ha0dd364_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.10.3-py312h6daa0e5_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.11-py312hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.22-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.18.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/fonttools-4.59.0-py312h6daa0e5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/freetype-2.13.3-hce30654_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-75.1-hfee45f7_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/id-1.5.0-pyh29332c3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.13-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.10-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.7.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.4.0-pyhd8ed1ab_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.context-6.0.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.functools-4.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/keyring-25.6.0-pyh534df25_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/kiwisolver-1.4.9-py312hdc12c9d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.21.3-h237132a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lcms2-2.17-h7eeda09_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lerc-4.0.0-hd64df32_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.9.0-34_h10e41b3_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlicommon-1.1.0-h5505292_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlidec-1.1.0-h5505292_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlienc-1.1.0-h5505292_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.9.0-34_hb3479ef_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.14.1-h73640d1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-20.1.8-hf598326_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libdeflate-1.24-h5773f1b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libev-4.33-h93a5062_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.7.1-hec049ff_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.6-h1da3d7d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libfreetype-2.13.3-hce30654_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libfreetype6-2.13.3-h1d14073_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.1.0-hfdf1602_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.1.0-hb74de2c_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libglib-2.84.3-h587fa63_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.18-h23cfdf5_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libintl-0.25.1-h493aca8_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libjpeg-turbo-3.1.0-h5505292_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.9.0-34_hc9a63f6_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.1-h39f12f2_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.64.0-h6d7220d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.30-openmp_h60d53f8_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libpng-1.6.50-h280e0eb_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.50.4-h4237e3c_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libtiff-4.7.0-h025e3ab_6.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.51.0-h6caf38d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libwebp-base-1.6.0-h07db88b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxcb-1.17.0-hdb1d25a_0.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/llvm-openmp-20.1.8-hbb9b287_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/matplotlib-3.10.5-py312h1f38498_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/matplotlib-base-3.10.5-py312h05635fa_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.7.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nh3-0.3.0-py39h24c5d98_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.9.1-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-24.4.1-hab9d20b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.3.2-py312h2f38b44_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.3-h889cd5d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.5.2-he92f556_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-2.3.1-py312h98f7732_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/patsy-1.0.1-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pcre2-10.45-ha881caa_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pillow-11.3.0-py312h50aef2c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pkg-config-0.29.2-hde07d2e_1009.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.8-pyhe01879c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.3.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pthread-stubs-0.4-hd74edd7_1002.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.3-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyright-1.1.399-py312hea69d52_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-8.4.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-6.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.11-hc22306f_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.11-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-8_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyyaml-6.0.2-py312h998013c_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/qhull-2020.2-h420ef59_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h1d1bf99_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/readme_renderer-44.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-1.0.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rfc3986-2.0.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/rhash-1.4.6-h5505292_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-14.1.0-pyhe01879c_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.16.1-py312h286a95b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/seaborn-0.13.2-hd8ed1ab_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/seaborn-base-0.13.2-pyhd8ed1ab_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/statsmodels-0.14.5-py312hcde60ef_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h892fb3f_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.2.1-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tornado-6.5.2-py312h163523d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/twine-6.1.0-pyh29332c3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.14.1-pyhe01879c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ukkonen-1.0.1-py312h6142ec9_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/unicodedata2-16.0.0-py312hea69d52_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.34.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.45.1-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xorg-libxau-1.0.12-h5505292_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xorg-libxdmcp-1.1.5-hd74edd7_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h925e9cb_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.23.0-py312hea69d52_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-h6491c7d_2.conda + - pypi: https://files.pythonhosted.org/packages/6f/12/e5e0282d673bb9746bacfb6e2dba8719989d3660cdb2ea79aee9a9651afb/anyio-4.10.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/54/5b/8b3b029c94c63ab4c1781d141615b4a837e658422381d460c5573d5d8262/biopython-1.85-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/21/e0/64716fb2ce9d7749bb41cc932c667b0f6d478e09367b36d273b1f77b06f3/biotite-1.4.0-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/c4/d2/369ed44ad23f8c0464f7b80d41143d717896097b39fe3dd3e07e6d162fef/biotraj-1.2.2-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/b6/6d/79fad38fcd7e1fc6961061b46cc87706c5c946088bc4620abf0d0aa49420/boto3-1.40.9-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/02/e9/367e81e114deb92a6e0d5740f0bff4548af710be318af65265b9aad72237/botocore-1.40.9-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/40/e7/6fea57b887f8e367c1e4a496ba03bfaf57824b766f777723ce1faf28834b/cloudpathlib-0.21.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/52/f2/9e726e4489f947557290605e3ee33b6ba09fe5dac9213263e0ada75200cf/dna_features_viewer-3.1.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/87/62/9773de14fe6c45c23649e98b83231fffd7b9892b6cf863251dc2afa73643/einops-0.8.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl + - pypi: direct+https://github.com/Dao-AILab/flash-attention/releases/download/v2.8.1/flash_attn-2.8.1+cu12torch2.7cxx11abiFALSE-cp312-cp312-linux_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/2f/e0/014d5d9d7a4564cf1c40b5039bc882db69fd881111e03ab3657ac0b218e2/fsspec-2025.7.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/51/a3/fa5897099454aa287022a34a30e68dbff0e617760f774f8bd1db17f06bd4/hf_xet-1.1.7-cp37-abi3-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/39/7b/bb06b061991107cd8783f300adff3e7b7f284e330fd82f507f2a1417b11d/huggingface_hub-0.34.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/63/f8/0031ee2b906a15a33d6bfc12dd09c3dfa966b3cb5b284ecfb7549e6ac3c4/ipython-9.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/58/6a/9166369a2f092bd286d24e6307de555d63616e8ddb373ebad2b5635ca4cd/ipywidgets-8.1.7-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7d/4f/1195bbac8e0c2acc5f740661631d8d750dc38d4a32b23ee5df3cde6f4e0d/joblib-1.5.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/43/6a/ca128561b22b60bd5a0c4ea26649e68c8556b82bc70a0c396eebc977fe86/jupyterlab_widgets-3.0.15-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ab/65/7d1de38c8a22cf8b1551469159d4b6cf49be2126adc2482de50976084d78/msgpack-1.1.1-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/9b/5d/f25ac7d4fb77cbd53ddc6d05d833c6bf52b12770a44fa9a447eed470ca9a/msgpack_numpy-0.4.8-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/eb/8d/776adee7bbf76365fdd7f2552710282c79a4ead5d2a46408c9043a2b70ba/networkx-3.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ce/4f/5249960887b1fbe561d9ff265496d170b55a735b76724f10ef19f9e40716/prompt_toolkit-3.0.51-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a3/17/c476487ba903c7d793db633b4e8ca4a420ae272890302189d9402ba8ff85/py3dmol-2.5.2-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/00/78/9cbcc1c073b9d4918e925af1a059762265dc65004e020511b2a06fbfd020/pydssp-0.9.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ec/cd/bd196b2cf014afb1009de8b0f05ecd54011d881944e62763f3c1b1e8ef37/pygtrie-2.5.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cd/70/69506d53397b4bd6954061bae75677ad34deb7f6ca3ba199660d6f728ff5/regex-2025.7.34-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/6d/4f/d073e09df851cfa251ef7840007d04db3293a0482ce607d2b993926089be/s3transfer-0.13.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8c/c9/bb114c158540ee17907ec470d01980957fdaf87b4aa07914c24eba87b9c6/safetensors-0.6.2-cp38-abi3-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/67/4e/899317092f5efcab0e9bc929e3391341cec8fb0e816c4789686770024580/scikit_learn-1.7.1-cp312-cp312-macosx_12_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/8d/a6/28975479e35ddc751dc1ddc97b9b69bf7fcf074db31548aab37f8116674c/tokenizers-0.21.4-cp39-abi3-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/be/66/5c9a321b325aaecb92d4d1855421e3a055abd77903b7dab6575ca07796db/torch-2.8.0-cp312-none-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/8b/80/c78f88844e576c21580e64bd93de9df9bca223fef3e8195345680eb6f87f/torchtext-0.18.0-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/df/1d/0ea0b34bde92a86d42620f29baa6dcbb5c2fc85990316df5cb8f7abb8ea2/torchvision-0.23.0-cp312-cp312-macosx_11_0_arm64.whl + - pypi: https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7b/9f/92d3091c44cb19add044064af1bf1345cd35fbb84d32a3690f912800a295/transformers-4.48.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ca/51/5447876806d1088a0f8f71e16542bf350918128d0a69437df26047c8e46f/widgetsnbextension-4.0.14-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/08/b8/2bc2590a34c733ea0570f366e6ad7d889d05c7825bd3ccab01f36ece71c6/zstd-1.5.7.2-cp312-cp312-macosx_11_0_arm64.whl + - pypi: ./ packages: - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 sha256: fe51de6107f9edc7aa4f786a70f4a883943bc9d39b3bb7307c04c41410990726 @@ -508,6 +953,17 @@ packages: purls: [] size: 8283 timestamp: 1736938720099 +- conda: https://conda.anaconda.org/conda-forge/noarch/_python_abi3_support-1.0-hd8ed1ab_2.conda + sha256: a3967b937b9abf0f2a99f3173fa4630293979bd1644709d89580e7c62a544661 + md5: aaa2a381ccc56eac91d63b6c1240312f + depends: + - cpython + - python-gil + license: MIT + license_family: MIT + purls: [] + size: 8191 + timestamp: 1744137672556 - conda: https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.14-hb9d3cd8_0.conda sha256: b9214bc17e89bf2b691fad50d952b7f029f6148f4ac4fe7c60c08f093efdf745 md5: 76df83c2a9035c54df5d04ff81bcc02d @@ -609,6 +1065,13 @@ packages: - pkg:pypi/backports-tarfile?source=hash-mapping size: 32786 timestamp: 1733325872620 +- pypi: https://files.pythonhosted.org/packages/54/5b/8b3b029c94c63ab4c1781d141615b4a837e658422381d460c5573d5d8262/biopython-1.85-cp312-cp312-macosx_11_0_arm64.whl + name: biopython + version: '1.85' + sha256: 6fe47d704c2d3afac99aeb461219ec5f00273120d2d99835dc0a9a617f520141 + requires_dist: + - numpy + requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/b4/0d/b7a0f10f5100dcf51ae36ba31490169bfa45617323bd82af43e1fb0098fb/biopython-1.85-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl name: biopython version: '1.85' @@ -632,6 +1095,22 @@ packages: - pytest ; extra == 'test' - pytest-codspeed ; extra == 'test' requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/21/e0/64716fb2ce9d7749bb41cc932c667b0f6d478e09367b36d273b1f77b06f3/biotite-1.4.0-cp312-cp312-macosx_11_0_arm64.whl + name: biotite + version: 1.4.0 + sha256: 19b4cfbdbe1ad94319dfea61d3dcdb07d476ba5bf55fb507021d6a5a5d4762d8 + requires_dist: + - biotraj>=1.0,<2.0 + - msgpack>=0.5.6 + - networkx>=2.0 + - numpy>=1.25 + - packaging>=24.0 + - requests>=2.12 + - numpydoc==1.8.0 ; extra == 'lint' + - ruff==0.9.7 ; extra == 'lint' + - pytest ; extra == 'test' + - pytest-codspeed ; extra == 'test' + requires_python: '>=3.11' - pypi: https://files.pythonhosted.org/packages/80/cd/c607b6337ddcf55cc0249527819b727ef28481d7c56ace54cca69400c2b9/biotraj-1.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl name: biotraj version: 1.2.2 @@ -644,6 +1123,39 @@ packages: - psutil ; extra == 'test' - netcdf4>=1.7.1 ; extra == 'test' requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/c4/d2/369ed44ad23f8c0464f7b80d41143d717896097b39fe3dd3e07e6d162fef/biotraj-1.2.2-cp312-cp312-macosx_11_0_arm64.whl + name: biotraj + version: 1.2.2 + sha256: 7bab65f5e3975a844c1018ea5873acd7dd21a64e8ebf0c145635c1d2fb9ef9bd + requires_dist: + - numpy>=1.25 + - scipy>=1.13 + - ruff==0.6.1 ; extra == 'lint' + - pytest ; extra == 'test' + - psutil ; extra == 'test' + - netcdf4>=1.7.1 ; extra == 'test' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/b6/6d/79fad38fcd7e1fc6961061b46cc87706c5c946088bc4620abf0d0aa49420/boto3-1.40.9-py3-none-any.whl + name: boto3 + version: 1.40.9 + sha256: 516f5e3f7552b2a7ca4d2c89b338fb4684998c676b11b906e2ab694c91716ba6 + requires_dist: + - botocore>=1.40.9,<1.41.0 + - jmespath>=0.7.1,<2.0.0 + - s3transfer>=0.13.0,<0.14.0 + - botocore[crt]>=1.21.0,<2.0a0 ; extra == 'crt' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/02/e9/367e81e114deb92a6e0d5740f0bff4548af710be318af65265b9aad72237/botocore-1.40.9-py3-none-any.whl + name: botocore + version: 1.40.9 + sha256: d4960a39aab9658bcd0272490003001cb4a8d12b89bb297ccef994ee023fb638 + requires_dist: + - jmespath>=0.7.1,<2.0.0 + - python-dateutil>=2.1,<3.0.0 + - urllib3>=1.25.4,<1.27 ; python_full_version < '3.10' + - urllib3>=1.25.4,!=2.2.0,<3 ; python_full_version >= '3.10' + - awscrt==0.23.8 ; extra == 'crt' + requires_python: '>=3.9' - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hb9d3cd8_2.conda sha256: fcb0b5b28ba7492093e54f3184435144e074dfceab27ac8e6a9457e736565b0b md5: 98514fe74548d768907ce7a13f680e8f @@ -658,6 +1170,19 @@ packages: purls: [] size: 19264 timestamp: 1725267697072 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-1.1.0-h5505292_3.conda + sha256: 97e2a90342869cc122921fdff0e6be2f5c38268555c08ba5d14e1615e4637e35 + md5: 03c7865dd4dbf87b7b7d363e24c632f1 + depends: + - __osx >=11.0 + - brotli-bin 1.1.0 h5505292_3 + - libbrotlidec 1.1.0 h5505292_3 + - libbrotlienc 1.1.0 h5505292_3 + license: MIT + license_family: MIT + purls: [] + size: 20094 + timestamp: 1749230390021 - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.1.0-hb9d3cd8_2.conda sha256: 261364d7445513b9a4debc345650fad13c627029bfc800655a266bf1e375bc65 md5: c63b5e52939e795ba8d26e35d767a843 @@ -671,6 +1196,18 @@ packages: purls: [] size: 18881 timestamp: 1725267688731 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-bin-1.1.0-h5505292_3.conda + sha256: 5c6a808326c3bbb6f015a57c9eb463d65f259f67154f4f06783d8829ce9239b4 + md5: cc435eb5160035fd8503e9a58036c5b5 + depends: + - __osx >=11.0 + - libbrotlidec 1.1.0 h5505292_3 + - libbrotlienc 1.1.0 h5505292_3 + license: MIT + license_family: MIT + purls: [] + size: 17185 + timestamp: 1749230373519 - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py312h2ec8cdc_2.conda sha256: f2a59ccd20b4816dea9a2a5cb917eb69728271dbf1aeab4e1b7e609330a50b6f md5: b0b867af6fc74b2a0aa206da29c0f3cf @@ -688,6 +1225,23 @@ packages: - pkg:pypi/brotli?source=hash-mapping size: 349867 timestamp: 1725267732089 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.1.0-py312hd8f9ff3_3.conda + sha256: 35df7079768b4c51764149c42b14ccc25c4415e4365ecc06c38f74562d9e4d16 + md5: c7c728df70dc05a443f1e337c28de22d + depends: + - __osx >=11.0 + - libcxx >=18 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + constrains: + - libbrotlicommon 1.1.0 h5505292_3 + license: MIT + license_family: MIT + purls: + - pkg:pypi/brotli?source=hash-mapping + size: 339365 + timestamp: 1749230606596 - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda sha256: 5ced96500d945fb286c9c838e54fa759aa04a7129c59800f0846b4335cee770d md5: 62ee74e96c5ebb0af99386de58cf9553 @@ -699,6 +1253,16 @@ packages: purls: [] size: 252783 timestamp: 1720974456583 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda + sha256: adfa71f158cbd872a36394c56c3568e6034aa55c623634b37a4836bd036e6b91 + md5: fc6948412dbbbe9a4c9ddbbcfe0a79ab + depends: + - __osx >=11.0 + license: bzip2-1.0.6 + license_family: BSD + purls: [] + size: 122909 + timestamp: 1720974522888 - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.4-hb9d3cd8_0.conda sha256: d4f28d87b6339b94f74762c0076e29c8ef8ddfff51a564a92da2843573c18320 md5: e2775acf57efd5af15b8e3d1d74d72d3 @@ -710,6 +1274,16 @@ packages: purls: [] size: 206085 timestamp: 1734208189009 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.5-h5505292_0.conda + sha256: b4bb55d0806e41ffef94d0e3f3c97531f322b3cb0ca1f7cdf8e47f62538b7a2b + md5: f8cd1beb98240c7edb1a95883360ccfa + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 179696 + timestamp: 1744128058734 - conda: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2025.1.31-hbcca054_0.conda sha256: bf832198976d559ab44d6cdb315642655547e26d826e34da67cbee6624cda189 md5: 19f3a56f68d2fd06c516076bff482c52 @@ -717,6 +1291,15 @@ packages: purls: [] size: 158144 timestamp: 1738298224464 +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.8.3-hbd8a1cb_0.conda + sha256: 837b795a2bb39b75694ba910c13c15fa4998d4bb2a622c214a6a5174b2ae53d1 + md5: 74784ee3d225fc3dca89edb635b4e5cc + depends: + - __unix + license: ISC + purls: [] + size: 154402 + timestamp: 1754210968730 - conda: https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.4-h3394656_0.conda sha256: 3bd6a391ad60e471de76c0e9db34986c4b5058587fbf2efa5a7f54645e28c2c7 md5: 09262e66b19567aff4f592fb53b28760 @@ -753,6 +1336,16 @@ packages: - pkg:pypi/certifi?source=compressed-mapping size: 162721 timestamp: 1739515973129 +- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2025.8.3-pyhd8ed1ab_0.conda + sha256: a1ad5b0a2a242f439608f22a538d2175cac4444b7b3f4e2b8c090ac337aaea40 + md5: 11f59985f49df4620890f3e746ed7102 + depends: + - python >=3.9 + license: ISC + purls: + - pkg:pypi/certifi?source=compressed-mapping + size: 158692 + timestamp: 1754231530168 - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-1.17.1-py312h06ac9bb_0.conda sha256: cba6ea83c4b0b4f5b5dc59cb19830519b28f95d7ebef7c9c5cf1c14843621457 md5: a861504bbea4161a9170b85d4d2be840 @@ -769,6 +1362,22 @@ packages: - pkg:pypi/cffi?source=hash-mapping size: 294403 timestamp: 1725560714366 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-1.17.1-py312h0fad829_0.conda + sha256: 8d91a0d01358b5c3f20297c6c536c5d24ccd3e0c2ddd37f9d0593d0f0070226f + md5: 19a5456f72f505881ba493979777b24e + depends: + - __osx >=11.0 + - libffi >=3.4,<4.0a0 + - pycparser + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cffi?source=hash-mapping + size: 281206 + timestamp: 1725560813378 - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.3.1-pyhd8ed1ab_1.conda sha256: d5696636733b3c301054b948cdd793f118efacce361d9bd4afb57d5980a9064f md5: 57df494053e17dce2ac3a0b33e1b2a2e @@ -791,6 +1400,17 @@ packages: - pkg:pypi/charset-normalizer?source=hash-mapping size: 47438 timestamp: 1735929811779 +- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.3-pyhd8ed1ab_0.conda + sha256: 838d5a011f0e7422be6427becba3de743c78f3874ad2743c341accbba9bb2624 + md5: 7e7d5ef1b9ed630e4a1c358d6bc62284 + depends: + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/charset-normalizer?source=hash-mapping + size: 51033 + timestamp: 1754767444665 - pypi: https://files.pythonhosted.org/packages/e8/0f/b1a9b09a84ef98b9fc38d50c6b2815cb2256b804a78e7d838ddfbdc035c7/cloudpathlib-0.21.0-py3-none-any.whl name: cloudpathlib version: 0.21.0 @@ -805,6 +1425,20 @@ packages: - google-cloud-storage ; extra == 'gs' - boto3>=1.34.0 ; extra == 's3' requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/40/e7/6fea57b887f8e367c1e4a496ba03bfaf57824b766f777723ce1faf28834b/cloudpathlib-0.21.1-py3-none-any.whl + name: cloudpathlib + version: 0.21.1 + sha256: bfe580ad72ec030472ec233cd7380701b2d3227da7b2898387bd170aa70c803c + requires_dist: + - typing-extensions>4 ; python_full_version < '3.11' + - cloudpathlib[azure] ; extra == 'all' + - cloudpathlib[gs] ; extra == 'all' + - cloudpathlib[s3] ; extra == 'all' + - azure-storage-blob>=12 ; extra == 'azure' + - azure-storage-file-datalake>=12 ; extra == 'azure' + - google-cloud-storage ; extra == 'gs' + - boto3>=1.34.0 ; extra == 's3' + requires_python: '>=3.9' - conda: https://conda.anaconda.org/conda-forge/linux-64/cmake-4.0.0-h74e3db0_0.conda sha256: 1178601b5969001e1797fdc8564a1bcb2d448a45ad20dacb233faaaeda6f794c md5: b8f039327d73a96c66c0e9c56d8c1cd8 @@ -826,6 +1460,26 @@ packages: purls: [] size: 20440638 timestamp: 1743111798861 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmake-4.1.0-hae74ae4_0.conda + sha256: 0e00e9c1944e594f293e10b4e4abd4505f098d8d63c95c455b80775abcf134fa + md5: 65d333c04dcdbea01b16993358df3364 + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libcurl >=8.14.1,<9.0a0 + - libcxx >=19 + - libexpat >=2.7.1,<3.0a0 + - liblzma >=5.8.1,<6.0a0 + - libuv >=1.51.0,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - rhash >=1.4.6,<2.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 16940415 + timestamp: 1754436958182 - conda: https://conda.anaconda.org/conda-forge/linux-64/cmarkgfm-2024.11.20-py312h66e93f0_0.conda sha256: 294643f1ad5cbaa8646f803b89cc2da2b43c41cf4d3855883662ab0bb5455d3e md5: bf99b4a864e31ecd9244affd27f3ceb6 @@ -841,6 +1495,21 @@ packages: - pkg:pypi/cmarkgfm?source=hash-mapping size: 139452 timestamp: 1732193337513 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmarkgfm-2024.11.20-py312hea69d52_0.conda + sha256: 8606d2948e8bdfe0f412e838f2329b47b44e281bc4229527a7de01b3e3a9432b + md5: 41c468aad74976b25c5726c660e662d8 + depends: + - __osx >=11.0 + - cffi >=1.0.0 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cmarkgfm?source=hash-mapping + size: 113005 + timestamp: 1732193458717 - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda sha256: ab29d57dc70786c1269633ba3dff20288b81664d3ff8d21af995742e2bb03287 md5: 962b9857ee8e7018c22f2776ffa0b2d7 @@ -852,9 +1521,16 @@ packages: - pkg:pypi/colorama?source=hash-mapping size: 27011 timestamp: 1733218222191 -- conda: https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.3-py312hd9148b4_1.conda - sha256: d9cb7f97a184a383bf0c72e1fa83b983a1caa68d7564f4449a4de7c97df9cb3f - md5: e25ed6c2e3b1effedfe9cd10a15ca8d8 +- pypi: https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl + name: comm + version: 0.2.3 + sha256: c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417 + requires_dist: + - pytest ; extra == 'test' + requires_python: '>=3.8' +- conda: https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.3-py312hd9148b4_1.conda + sha256: d9cb7f97a184a383bf0c72e1fa83b983a1caa68d7564f4449a4de7c97df9cb3f + md5: e25ed6c2e3b1effedfe9cd10a15ca8d8 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 @@ -868,6 +1544,22 @@ packages: - pkg:pypi/contourpy?source=compressed-mapping size: 291827 timestamp: 1754063770363 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/contourpy-1.3.3-py312ha0dd364_1.conda + sha256: a51a6f7f7e236cadc45790880dc0b7c91cf6a950277ffe839b689f072783a8d0 + md5: e0b0bffaccf76ef33679dd2e5309442e + depends: + - __osx >=11.0 + - libcxx >=19 + - numpy >=1.25 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/contourpy?source=hash-mapping + size: 257410 + timestamp: 1754063952152 - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.10.2-py312h8a5da7c_0.conda sha256: 211754cf4be7ce64b11955509fcab60cd33090633c362d4aface4a5320adbf77 md5: f8830a2249f4b8a5f9c33cb44ad5c31a @@ -883,6 +1575,32 @@ packages: - pkg:pypi/coverage?source=hash-mapping size: 377963 timestamp: 1754308562631 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.10.3-py312h6daa0e5_0.conda + sha256: 5395c4d622d56fbab9489136b7daf254d325fe2101bdb95f91c78dc88e0da2ad + md5: 724b721d0f9a50826207779456d2c172 + depends: + - __osx >=11.0 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + - tomli + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/coverage?source=hash-mapping + size: 380056 + timestamp: 1754910268875 +- conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.11-py312hd8ed1ab_0.conda + noarch: generic + sha256: 7e7bc8e73a2f3736444a8564cbece7216464c00f0bc38e604b0c792ff60d621a + md5: e5279009e7a7f7edd3cd2880c502b3cc + depends: + - python >=3.12,<3.13.0a0 + - python_abi * *_cp312 + license: Python-2.0 + purls: [] + size: 45852 + timestamp: 1749047748072 - conda: https://conda.anaconda.org/conda-forge/noarch/cpython-3.12.9-py312hd8ed1ab_1.conda noarch: generic sha256: 58a637bc8328b115c9619de3fcd664ec26662083319e3c106917a1b3ee4d7594 @@ -965,6 +1683,14 @@ packages: - pkg:pypi/distlib?source=hash-mapping size: 275642 timestamp: 1752823081585 +- pypi: https://files.pythonhosted.org/packages/52/f2/9e726e4489f947557290605e3ee33b6ba09fe5dac9213263e0ada75200cf/dna_features_viewer-3.1.5-py3-none-any.whl + name: dna-features-viewer + version: 3.1.5 + sha256: a8a383d5340d35979be50224f12f4f426ab004394d9b9a33c99d59404469fb7a + requires_dist: + - matplotlib>=3 + - biopython + - packaging - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_1.conda sha256: fa5966bb1718bbf6967a85075e30e4547901410cc7cb7b16daf68942e9a94823 md5: 24c1ca34138ee57de72a943237cde4cc @@ -975,6 +1701,16 @@ packages: - pkg:pypi/docutils?source=hash-mapping size: 402700 timestamp: 1733217860944 +- conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.22-pyhd8ed1ab_0.conda + sha256: dd585e49f231ec414e6550783f2aff85027fa829e5d66004ad702e1cfa6324aa + md5: 140faac6cff4382f5ea077ca618b2931 + depends: + - python >=3.9 + license: CC-PDDC AND BSD-3-Clause AND BSD-2-Clause AND ZPL-2.1 + purls: + - pkg:pypi/docutils?source=hash-mapping + size: 436452 + timestamp: 1753875179563 - conda: https://conda.anaconda.org/conda-forge/linux-64/double-conversion-3.3.1-h5888daf_0.conda sha256: 1bcc132fbcc13f9ad69da7aa87f60ea41de7ed4d09f3a00ff6e0e70e1c690bc2 md5: bfd56492d8346d669010eccafe0ba058 @@ -995,7 +1731,7 @@ packages: - pypi: ./ name: esm version: 3.2.1 - sha256: 8bf7da0d570fb088244c8ce31ae949a0da6409e924aa756929fe01266401cd0b + sha256: 5456e12b3d09b96bb576d68a9f74ea445e11a4936b72488d878d0149523b0870 requires_dist: - torch>=2.2.0 - torchvision @@ -1014,7 +1750,14 @@ packages: - httpx - tenacity - zstd - requires_python: '>=3.10' + - ipywidgets + - py3dmol + - pydssp + - boto3 + - pygtrie + - dna-features-viewer + - flash-attn @ https://github.com/Dao-AILab/flash-attention/releases/download/v2.8.1/flash_attn-2.8.1+cu12torch2.7cxx11abiFALSE-cp312-cp312-linux_x86_64.whl + requires_python: '>=3.10,<3.13' editable: true - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda sha256: ce61f4f99401a4bd455b89909153b40b9c823276aefcbb06f2044618696009ca @@ -1027,6 +1770,17 @@ packages: - pkg:pypi/exceptiongroup?source=hash-mapping size: 21284 timestamp: 1746947398083 +- conda: https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_1.conda + sha256: 9abc6c128cd40733e9b24284d0462e084d4aff6afe614f0754aa8533ebe505e4 + md5: a71efeae2c160f6789900ba2631a2c90 + depends: + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/execnet?source=hash-mapping + size: 38835 + timestamp: 1733231086305 - pypi: https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl name: executing version: 2.2.0 @@ -1062,6 +1816,13 @@ packages: - pkg:pypi/filelock?source=hash-mapping size: 17887 timestamp: 1741969612334 +- pypi: direct+https://github.com/Dao-AILab/flash-attention/releases/download/v2.8.1/flash_attn-2.8.1+cu12torch2.7cxx11abiFALSE-cp312-cp312-linux_x86_64.whl + name: flash-attn + version: 2.8.1 + requires_dist: + - torch + - einops + requires_python: '>=3.9' - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 sha256: 58d7f40d2940dd0a8aa28651239adbf5613254df0f75789919c4e6762054403b md5: 0c96522c6bdaed4b1566d11387caaf45 @@ -1149,6 +1910,23 @@ packages: - pkg:pypi/fonttools?source=hash-mapping size: 2854951 timestamp: 1752723143 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/fonttools-4.59.0-py312h6daa0e5_0.conda + sha256: fb5dabc7db09891e611723622c762f625f287fc54d1f914497baf95b713513c3 + md5: 0fed8437f0bd51c23d4caa1a61fe7b3b + depends: + - __osx >=11.0 + - brotli + - munkres + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + - unicodedata2 >=15.1.0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/fonttools?source=hash-mapping + size: 2794146 + timestamp: 1752723166136 - conda: https://conda.anaconda.org/conda-forge/linux-64/freetype-2.13.3-ha770c72_1.conda sha256: 7ef7d477c43c12a5b4cddcf048a83277414512d1116aba62ebadfa7056a7d84f md5: 9ccd736d31e0c6e41f54e704e5312811 @@ -1159,6 +1937,16 @@ packages: purls: [] size: 172450 timestamp: 1745369996765 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/freetype-2.13.3-hce30654_1.conda + sha256: 6b63c72ea51a41d41964841404564c0729fdddd3e952e2715839fd759b7cfdfc + md5: e684de4644067f1956a580097502bf03 + depends: + - libfreetype 2.13.3 hce30654_1 + - libfreetype6 2.13.3 h1d14073_1 + license: GPL-2.0-only OR FTL + purls: [] + size: 172220 + timestamp: 1745370149658 - pypi: https://files.pythonhosted.org/packages/44/4b/e0cfc1a6f17e990f3e64b7d941ddc4acdc7b19d6edd51abf495f32b1a9e4/fsspec-2025.3.2-py3-none-any.whl name: fsspec version: 2025.3.2 @@ -1266,6 +2054,113 @@ packages: - zstandard ; extra == 'test-full' - tqdm ; extra == 'tqdm' requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/2f/e0/014d5d9d7a4564cf1c40b5039bc882db69fd881111e03ab3657ac0b218e2/fsspec-2025.7.0-py3-none-any.whl + name: fsspec + version: 2025.7.0 + sha256: 8b012e39f63c7d5f10474de957f3ab793b47b45ae7d39f2fb735f8bbe25c0e21 + requires_dist: + - adlfs ; extra == 'abfs' + - adlfs ; extra == 'adl' + - pyarrow>=1 ; extra == 'arrow' + - dask ; extra == 'dask' + - distributed ; extra == 'dask' + - pre-commit ; extra == 'dev' + - ruff>=0.5 ; extra == 'dev' + - numpydoc ; extra == 'doc' + - sphinx ; extra == 'doc' + - sphinx-design ; extra == 'doc' + - sphinx-rtd-theme ; extra == 'doc' + - yarl ; extra == 'doc' + - dropbox ; extra == 'dropbox' + - dropboxdrivefs ; extra == 'dropbox' + - requests ; extra == 'dropbox' + - adlfs ; extra == 'full' + - aiohttp!=4.0.0a0,!=4.0.0a1 ; extra == 'full' + - dask ; extra == 'full' + - distributed ; extra == 'full' + - dropbox ; extra == 'full' + - dropboxdrivefs ; extra == 'full' + - fusepy ; extra == 'full' + - gcsfs ; extra == 'full' + - libarchive-c ; extra == 'full' + - ocifs ; extra == 'full' + - panel ; extra == 'full' + - paramiko ; extra == 'full' + - pyarrow>=1 ; extra == 'full' + - pygit2 ; extra == 'full' + - requests ; extra == 'full' + - s3fs ; extra == 'full' + - smbprotocol ; extra == 'full' + - tqdm ; extra == 'full' + - fusepy ; extra == 'fuse' + - gcsfs ; extra == 'gcs' + - pygit2 ; extra == 'git' + - requests ; extra == 'github' + - gcsfs ; extra == 'gs' + - panel ; extra == 'gui' + - pyarrow>=1 ; extra == 'hdfs' + - aiohttp!=4.0.0a0,!=4.0.0a1 ; extra == 'http' + - libarchive-c ; extra == 'libarchive' + - ocifs ; extra == 'oci' + - s3fs ; extra == 's3' + - paramiko ; extra == 'sftp' + - smbprotocol ; extra == 'smb' + - paramiko ; extra == 'ssh' + - aiohttp!=4.0.0a0,!=4.0.0a1 ; extra == 'test' + - numpy ; extra == 'test' + - pytest ; extra == 'test' + - pytest-asyncio!=0.22.0 ; extra == 'test' + - pytest-benchmark ; extra == 'test' + - pytest-cov ; extra == 'test' + - pytest-mock ; extra == 'test' + - pytest-recording ; extra == 'test' + - pytest-rerunfailures ; extra == 'test' + - requests ; extra == 'test' + - aiobotocore>=2.5.4,<3.0.0 ; extra == 'test-downstream' + - dask[dataframe,test] ; extra == 'test-downstream' + - moto[server]>4,<5 ; extra == 'test-downstream' + - pytest-timeout ; extra == 'test-downstream' + - xarray ; extra == 'test-downstream' + - adlfs ; extra == 'test-full' + - aiohttp!=4.0.0a0,!=4.0.0a1 ; extra == 'test-full' + - cloudpickle ; extra == 'test-full' + - dask ; extra == 'test-full' + - distributed ; extra == 'test-full' + - dropbox ; extra == 'test-full' + - dropboxdrivefs ; extra == 'test-full' + - fastparquet ; extra == 'test-full' + - fusepy ; extra == 'test-full' + - gcsfs ; extra == 'test-full' + - jinja2 ; extra == 'test-full' + - kerchunk ; extra == 'test-full' + - libarchive-c ; extra == 'test-full' + - lz4 ; extra == 'test-full' + - notebook ; extra == 'test-full' + - numpy ; extra == 'test-full' + - ocifs ; extra == 'test-full' + - pandas ; extra == 'test-full' + - panel ; extra == 'test-full' + - paramiko ; extra == 'test-full' + - pyarrow ; extra == 'test-full' + - pyarrow>=1 ; extra == 'test-full' + - pyftpdlib ; extra == 'test-full' + - pygit2 ; extra == 'test-full' + - pytest ; extra == 'test-full' + - pytest-asyncio!=0.22.0 ; extra == 'test-full' + - pytest-benchmark ; extra == 'test-full' + - pytest-cov ; extra == 'test-full' + - pytest-mock ; extra == 'test-full' + - pytest-recording ; extra == 'test-full' + - pytest-rerunfailures ; extra == 'test-full' + - python-snappy ; extra == 'test-full' + - requests ; extra == 'test-full' + - smbprotocol ; extra == 'test-full' + - tqdm ; extra == 'test-full' + - urllib3 ; extra == 'test-full' + - zarr ; extra == 'test-full' + - zstandard ; python_full_version < '3.14' and extra == 'test-full' + - tqdm ; extra == 'tqdm' + requires_python: '>=3.9' - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.14-hecca717_1.conda sha256: 060dbb9e8f025cd09819586dd9c5a9c29bfcff0ac222435c90f4a83655caef7e md5: d8f05f0493cacd0b29cbc0049669151f @@ -1317,6 +2212,13 @@ packages: purls: [] size: 1730226 timestamp: 1747091044218 +- pypi: https://files.pythonhosted.org/packages/51/a3/fa5897099454aa287022a34a30e68dbff0e617760f774f8bd1db17f06bd4/hf_xet-1.1.7-cp37-abi3-macosx_11_0_arm64.whl + name: hf-xet + version: 1.1.7 + sha256: b109f4c11e01c057fc82004c9e51e6cdfe2cb230637644ade40c599739067b2e + requires_dist: + - pytest ; extra == 'tests' + requires_python: '>=3.8' - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda sha256: 6ad78a180576c706aabeb5b4c8ceb97c0cb25f1e112d76495bff23e3779948ba md5: 0a802cb9888dd14eeefc611f05c40b6e @@ -1469,6 +2371,137 @@ packages: - types-tqdm ; extra == 'typing' - types-urllib3 ; extra == 'typing' requires_python: '>=3.8.0' +- pypi: https://files.pythonhosted.org/packages/39/7b/bb06b061991107cd8783f300adff3e7b7f284e330fd82f507f2a1417b11d/huggingface_hub-0.34.4-py3-none-any.whl + name: huggingface-hub + version: 0.34.4 + sha256: 9b365d781739c93ff90c359844221beef048403f1bc1f1c123c191257c3c890a + requires_dist: + - filelock + - fsspec>=2023.5.0 + - packaging>=20.9 + - pyyaml>=5.1 + - requests + - tqdm>=4.42.1 + - typing-extensions>=3.7.4.3 + - hf-xet>=1.1.3,<2.0.0 ; platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64' + - inquirerpy==0.3.4 ; extra == 'all' + - aiohttp ; extra == 'all' + - authlib>=1.3.2 ; extra == 'all' + - fastapi ; extra == 'all' + - httpx ; extra == 'all' + - itsdangerous ; extra == 'all' + - jedi ; extra == 'all' + - jinja2 ; extra == 'all' + - pytest>=8.1.1,<8.2.2 ; extra == 'all' + - pytest-cov ; extra == 'all' + - pytest-env ; extra == 'all' + - pytest-xdist ; extra == 'all' + - pytest-vcr ; extra == 'all' + - pytest-asyncio ; extra == 'all' + - pytest-rerunfailures ; extra == 'all' + - pytest-mock ; extra == 'all' + - urllib3<2.0 ; extra == 'all' + - soundfile ; extra == 'all' + - pillow ; extra == 'all' + - gradio>=4.0.0 ; extra == 'all' + - numpy ; extra == 'all' + - ruff>=0.9.0 ; extra == 'all' + - libcst>=1.4.0 ; extra == 'all' + - typing-extensions>=4.8.0 ; extra == 'all' + - types-pyyaml ; extra == 'all' + - types-requests ; extra == 'all' + - types-simplejson ; extra == 'all' + - types-toml ; extra == 'all' + - types-tqdm ; extra == 'all' + - types-urllib3 ; extra == 'all' + - mypy>=1.14.1,<1.15.0 ; python_full_version == '3.8.*' and extra == 'all' + - mypy==1.15.0 ; python_full_version >= '3.9' and extra == 'all' + - inquirerpy==0.3.4 ; extra == 'cli' + - inquirerpy==0.3.4 ; extra == 'dev' + - aiohttp ; extra == 'dev' + - authlib>=1.3.2 ; extra == 'dev' + - fastapi ; extra == 'dev' + - httpx ; extra == 'dev' + - itsdangerous ; extra == 'dev' + - jedi ; extra == 'dev' + - jinja2 ; extra == 'dev' + - pytest>=8.1.1,<8.2.2 ; extra == 'dev' + - pytest-cov ; extra == 'dev' + - pytest-env ; extra == 'dev' + - pytest-xdist ; extra == 'dev' + - pytest-vcr ; extra == 'dev' + - pytest-asyncio ; extra == 'dev' + - pytest-rerunfailures ; extra == 'dev' + - pytest-mock ; extra == 'dev' + - urllib3<2.0 ; extra == 'dev' + - soundfile ; extra == 'dev' + - pillow ; extra == 'dev' + - gradio>=4.0.0 ; extra == 'dev' + - numpy ; extra == 'dev' + - ruff>=0.9.0 ; extra == 'dev' + - libcst>=1.4.0 ; extra == 'dev' + - typing-extensions>=4.8.0 ; extra == 'dev' + - types-pyyaml ; extra == 'dev' + - types-requests ; extra == 'dev' + - types-simplejson ; extra == 'dev' + - types-toml ; extra == 'dev' + - types-tqdm ; extra == 'dev' + - types-urllib3 ; extra == 'dev' + - mypy>=1.14.1,<1.15.0 ; python_full_version == '3.8.*' and extra == 'dev' + - mypy==1.15.0 ; python_full_version >= '3.9' and extra == 'dev' + - toml ; extra == 'fastai' + - fastai>=2.4 ; extra == 'fastai' + - fastcore>=1.3.27 ; extra == 'fastai' + - hf-transfer>=0.1.4 ; extra == 'hf-transfer' + - hf-xet>=1.1.2,<2.0.0 ; extra == 'hf-xet' + - aiohttp ; extra == 'inference' + - mcp>=1.8.0 ; extra == 'mcp' + - typer ; extra == 'mcp' + - aiohttp ; extra == 'mcp' + - authlib>=1.3.2 ; extra == 'oauth' + - fastapi ; extra == 'oauth' + - httpx ; extra == 'oauth' + - itsdangerous ; extra == 'oauth' + - ruff>=0.9.0 ; extra == 'quality' + - libcst>=1.4.0 ; extra == 'quality' + - mypy>=1.14.1,<1.15.0 ; python_full_version == '3.8.*' and extra == 'quality' + - mypy==1.15.0 ; python_full_version >= '3.9' and extra == 'quality' + - tensorflow ; extra == 'tensorflow' + - pydot ; extra == 'tensorflow' + - graphviz ; extra == 'tensorflow' + - tensorflow ; extra == 'tensorflow-testing' + - keras<3.0 ; extra == 'tensorflow-testing' + - inquirerpy==0.3.4 ; extra == 'testing' + - aiohttp ; extra == 'testing' + - authlib>=1.3.2 ; extra == 'testing' + - fastapi ; extra == 'testing' + - httpx ; extra == 'testing' + - itsdangerous ; extra == 'testing' + - jedi ; extra == 'testing' + - jinja2 ; extra == 'testing' + - pytest>=8.1.1,<8.2.2 ; extra == 'testing' + - pytest-cov ; extra == 'testing' + - pytest-env ; extra == 'testing' + - pytest-xdist ; extra == 'testing' + - pytest-vcr ; extra == 'testing' + - pytest-asyncio ; extra == 'testing' + - pytest-rerunfailures ; extra == 'testing' + - pytest-mock ; extra == 'testing' + - urllib3<2.0 ; extra == 'testing' + - soundfile ; extra == 'testing' + - pillow ; extra == 'testing' + - gradio>=4.0.0 ; extra == 'testing' + - numpy ; extra == 'testing' + - torch ; extra == 'torch' + - safetensors[torch] ; extra == 'torch' + - typing-extensions>=4.8.0 ; extra == 'typing' + - types-pyyaml ; extra == 'typing' + - types-requests ; extra == 'typing' + - types-simplejson ; extra == 'typing' + - types-toml ; extra == 'typing' + - types-tqdm ; extra == 'typing' + - types-urllib3 ; extra == 'typing' + requires_python: '>=3.8.0' - conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda sha256: 77af6f5fe8b62ca07d09ac60127a30d9069fdc3c68d6b256754d0ffb1f7779f8 md5: 8e6923fc12f1fe8f8c4e5c9f343256ac @@ -1492,6 +2525,16 @@ packages: purls: [] size: 12129203 timestamp: 1720853576813 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-75.1-hfee45f7_0.conda + sha256: 9ba12c93406f3df5ab0a43db8a4b4ef67a5871dfd401010fbe29b218b2cbe620 + md5: 5eb22c1d7b3fc4abb50d92d621583137 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 11857802 + timestamp: 1720853997952 - conda: https://conda.anaconda.org/conda-forge/noarch/id-1.5.0-pyh29332c3_0.conda sha256: 161e3eb5aba887d0329bb4099f72cb92eed9072cf63f551d08540480116e69a2 md5: d37314c8f553e3b4b44d113a0ee10196 @@ -1517,6 +2560,18 @@ packages: - pkg:pypi/identify?source=hash-mapping size: 78926 timestamp: 1748049754416 +- conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.13-pyhd8ed1ab_0.conda + sha256: 7183512c24050c541d332016c1dd0f2337288faf30afc42d60981a49966059f7 + md5: 52083ce9103ec11c8130ce18517d3e83 + depends: + - python >=3.9 + - ukkonen + license: MIT + license_family: MIT + purls: + - pkg:pypi/identify?source=hash-mapping + size: 79080 + timestamp: 1754777609249 - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.10-pyhd8ed1ab_1.conda sha256: d7a472c9fd479e2e8dcb83fb8d433fce971ea369d704ece380e876f9c3494e87 md5: 39a4f67be3286c86d696df570b1201b7 @@ -1540,6 +2595,19 @@ packages: - pkg:pypi/importlib-metadata?source=compressed-mapping size: 29141 timestamp: 1737420302391 +- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.7.0-pyhe01879c_1.conda + sha256: c18ab120a0613ada4391b15981d86ff777b5690ca461ea7e9e49531e8f374745 + md5: 63ccfdc3a3ce25b027b8767eb722fca8 + depends: + - python >=3.9 + - zipp >=3.20 + - python + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/importlib-metadata?source=hash-mapping + size: 34641 + timestamp: 1747934053147 - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda sha256: acc1d991837c0afb67c75b77fdc72b4bf022aac71fedd8b9ea45918ac9b08a80 md5: c85c76dc67d75619a92f51dfbce06992 @@ -1607,6 +2675,51 @@ packages: - matplotlib ; extra == 'matplotlib' - ipython[doc,matplotlib,test,test-extra] ; extra == 'all' requires_python: '>=3.11' +- pypi: https://files.pythonhosted.org/packages/63/f8/0031ee2b906a15a33d6bfc12dd09c3dfa966b3cb5b284ecfb7549e6ac3c4/ipython-9.4.0-py3-none-any.whl + name: ipython + version: 9.4.0 + sha256: 25850f025a446d9b359e8d296ba175a36aedd32e83ca9b5060430fe16801f066 + requires_dist: + - colorama ; sys_platform == 'win32' + - decorator + - ipython-pygments-lexers + - jedi>=0.16 + - matplotlib-inline + - pexpect>4.3 ; sys_platform != 'emscripten' and sys_platform != 'win32' + - prompt-toolkit>=3.0.41,<3.1.0 + - pygments>=2.4.0 + - stack-data + - traitlets>=5.13.0 + - typing-extensions>=4.6 ; python_full_version < '3.12' + - black ; extra == 'black' + - docrepr ; extra == 'doc' + - exceptiongroup ; extra == 'doc' + - intersphinx-registry ; extra == 'doc' + - ipykernel ; extra == 'doc' + - ipython[test] ; extra == 'doc' + - matplotlib ; extra == 'doc' + - setuptools>=18.5 ; extra == 'doc' + - sphinx-toml==0.0.4 ; extra == 'doc' + - sphinx-rtd-theme ; extra == 'doc' + - sphinx>=1.3 ; extra == 'doc' + - typing-extensions ; extra == 'doc' + - pytest ; extra == 'test' + - pytest-asyncio<0.22 ; extra == 'test' + - testpath ; extra == 'test' + - packaging ; extra == 'test' + - ipython[test] ; extra == 'test-extra' + - curio ; extra == 'test-extra' + - jupyter-ai ; extra == 'test-extra' + - matplotlib!=3.2.0 ; extra == 'test-extra' + - nbformat ; extra == 'test-extra' + - nbclient ; extra == 'test-extra' + - ipykernel ; extra == 'test-extra' + - numpy>=1.23 ; extra == 'test-extra' + - pandas ; extra == 'test-extra' + - trio ; extra == 'test-extra' + - matplotlib ; extra == 'matplotlib' + - ipython[doc,matplotlib,test,test-extra] ; extra == 'all' + requires_python: '>=3.11' - pypi: https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl name: ipython-pygments-lexers version: 1.1.1 @@ -1614,6 +2727,22 @@ packages: requires_dist: - pygments requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/58/6a/9166369a2f092bd286d24e6307de555d63616e8ddb373ebad2b5635ca4cd/ipywidgets-8.1.7-py3-none-any.whl + name: ipywidgets + version: 8.1.7 + sha256: 764f2602d25471c213919b8a1997df04bef869251db4ca8efba1b76b1bd9f7bb + requires_dist: + - comm>=0.1.3 + - ipython>=6.1.0 + - traitlets>=4.3.1 + - widgetsnbextension~=4.0.14 + - jupyterlab-widgets~=3.0.15 + - jsonschema ; extra == 'test' + - ipykernel ; extra == 'test' + - pytest>=3.6.0 ; extra == 'test' + - pytest-cov ; extra == 'test' + - pytz ; extra == 'test' + requires_python: '>=3.7' - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.4.0-pyhd8ed1ab_2.conda sha256: 3d16a0fa55a29fe723c918a979b2ee927eb0bf9616381cdfd26fa9ea2b649546 md5: ade6b25a6136661dadd1a43e4350b10b @@ -1650,6 +2779,18 @@ packages: - pkg:pypi/jaraco-functools?source=hash-mapping size: 15545 timestamp: 1733746481844 +- conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.functools-4.2.1-pyhd8ed1ab_0.conda + sha256: f132ac71f89e3133fe159034ec85cec946c75f2c60e2039a8bbd1012721a785e + md5: c2c206c4054db7a655761c9e5bbb11f7 + depends: + - more-itertools + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/jaraco-functools?source=hash-mapping + size: 16187 + timestamp: 1751918863003 - pypi: https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl name: jedi version: 0.19.2 @@ -1709,11 +2850,43 @@ packages: - markupsafe>=2.0 - babel>=2.7 ; extra == 'i18n' requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl + name: jmespath + version: 1.0.1 + sha256: 02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980 + requires_python: '>=3.7' - pypi: https://files.pythonhosted.org/packages/91/29/df4b9b42f2be0b623cbd5e2140cafcaa2bef0759a00b7b70104dcfe2fb51/joblib-1.4.2-py3-none-any.whl name: joblib version: 1.4.2 sha256: 06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6 requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/7d/4f/1195bbac8e0c2acc5f740661631d8d750dc38d4a32b23ee5df3cde6f4e0d/joblib-1.5.1-py3-none-any.whl + name: joblib + version: 1.5.1 + sha256: 4719a31f054c7d766948dcd83e9613686b27114f190f717cec7eaa2084f8a74a + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/43/6a/ca128561b22b60bd5a0c4ea26649e68c8556b82bc70a0c396eebc977fe86/jupyterlab_widgets-3.0.15-py3-none-any.whl + name: jupyterlab-widgets + version: 3.0.15 + sha256: d59023d7d7ef71400d51e6fee9a88867f6e65e10a4201605d2d7f3e8f012a31c + requires_python: '>=3.7' +- conda: https://conda.anaconda.org/conda-forge/noarch/keyring-25.6.0-pyh534df25_0.conda + sha256: c8b436fa9853bf8b836c96afbb7684a04955b80b37f5d5285fd836b6a8566cc5 + md5: d2c0c5bda93c249f877c7fceea9e63af + depends: + - __osx + - importlib-metadata >=4.11.4 + - importlib_resources + - jaraco.classes + - jaraco.context + - jaraco.functools + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/keyring?source=hash-mapping + size: 37280 + timestamp: 1735210369348 - conda: https://conda.anaconda.org/conda-forge/noarch/keyring-25.6.0-pyha804496_0.conda sha256: b6f57c17cf098022c32fe64e85e9615d427a611c48a5947cdfc357490210a124 md5: cdd58ab99c214b55d56099108a914282 @@ -1757,6 +2930,21 @@ packages: - pkg:pypi/kiwisolver?source=hash-mapping size: 72166 timestamp: 1751493973594 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/kiwisolver-1.4.9-py312hdc12c9d_0.conda + sha256: 290d8f1016c9581bd4d2246bb21832ba4e4ba1c7b059eb9106d92bba561bccc7 + md5: 91384df8de4c340a1232793cf39a12ce + depends: + - python + - python 3.12.* *_cpython + - libcxx >=19 + - __osx >=11.0 + - python_abi 3.12.* *_cp312 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/kiwisolver?source=hash-mapping + size: 67692 + timestamp: 1754889447292 - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda sha256: 99df692f7a8a5c27cd14b5fb1374ee55e756631b9c3d659ed3ee60830249b238 md5: 3f43953b7d3fb3aaa1d0d0723d91e368 @@ -1772,6 +2960,20 @@ packages: purls: [] size: 1370023 timestamp: 1719463201255 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.21.3-h237132a_0.conda + sha256: 4442f957c3c77d69d9da3521268cad5d54c9033f1a73f99cde0a3658937b159b + md5: c6dc8a0fdec13a0565936655c33069a1 + depends: + - __osx >=11.0 + - libcxx >=16 + - libedit >=3.1.20191231,<3.2.0a0 + - libedit >=3.1.20191231,<4.0a0 + - openssl >=3.3.1,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 1155530 + timestamp: 1719463474401 - conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.17-h717163a_0.conda sha256: d6a61830a354da022eae93fa896d0991385a875c6bba53c82263a289deda9db8 md5: 000e85703f0fd9594c81710dd5066471 @@ -1785,6 +2987,18 @@ packages: purls: [] size: 248046 timestamp: 1739160907615 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/lcms2-2.17-h7eeda09_0.conda + sha256: 310a62c2f074ebd5aa43b3cd4b00d46385ce680fa2132ecee255a200e2d2f15f + md5: 92a61fd30b19ebd5c1621a5bfe6d8b5f + depends: + - __osx >=11.0 + - libjpeg-turbo >=3.0.0,<4.0a0 + - libtiff >=4.7.0,<4.8.0a0 + license: MIT + license_family: MIT + purls: [] + size: 212125 + timestamp: 1739161108467 - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_4.conda sha256: db73f38155d901a610b2320525b9dd3b31e4949215c870685fd92ea61b5ce472 md5: 01f8d123c96816249efd255a31ad7712 @@ -1809,6 +3023,17 @@ packages: purls: [] size: 264243 timestamp: 1745264221534 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/lerc-4.0.0-hd64df32_1.conda + sha256: 12361697f8ffc9968907d1a7b5830e34c670e4a59b638117a2cdfed8f63a38f8 + md5: a74332d9b60b62905e3d30709df08bf1 + depends: + - __osx >=11.0 + - libcxx >=18 + license: Apache-2.0 + license_family: Apache + purls: [] + size: 188306 + timestamp: 1745264362794 - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-31_h59b9bed_openblas.conda build_number: 31 sha256: 9839fc4ac0cbb0aa3b9eea520adfb57311838959222654804e58f6f2d1771db5 @@ -1827,6 +3052,24 @@ packages: purls: [] size: 16859 timestamp: 1740087969120 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.9.0-34_h10e41b3_openblas.conda + build_number: 34 + sha256: 5de3c3bfcdc8ba05da1a7815c9953fe392c2065d9efdc2491f91df6d0d1d9e76 + md5: cdb3e1ca1661dbf19f9aad7dad524996 + depends: + - libopenblas >=0.3.30,<0.3.31.0a0 + - libopenblas >=0.3.30,<1.0a0 + constrains: + - blas 2.134 openblas + - mkl <2025 + - liblapacke 3.9.0 34*_openblas + - libcblas 3.9.0 34*_openblas + - liblapack 3.9.0 34*_openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 19533 + timestamp: 1754678956963 - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hb9d3cd8_2.conda sha256: d9db2de60ea917298e658143354a530e9ca5f9c63471c65cf47ab39fd2f429e3 md5: 41b599ed2b02abcfdd84302bff174b23 @@ -1838,6 +3081,16 @@ packages: purls: [] size: 68851 timestamp: 1725267660471 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlicommon-1.1.0-h5505292_3.conda + sha256: 0e9c196ad8569ca199ea05103707cde0ae3c7e97d0cdf0417d873148ea9ad640 + md5: fbc4d83775515e433ef22c058768b84d + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 68972 + timestamp: 1749230317752 - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.1.0-hb9d3cd8_2.conda sha256: 2892d512cad096cb03f1b66361deeab58b64e15ba525d6592bb6d609e7045edf md5: 9566f0bd264fbd463002e759b8a82401 @@ -1850,6 +3103,17 @@ packages: purls: [] size: 32696 timestamp: 1725267669305 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlidec-1.1.0-h5505292_3.conda + sha256: d888c228e7d4f0f2303538f6a9705498c81d56fedaab7811e1186cb6e24d689b + md5: 01c4b35a1c4b94b60801f189f1ac6ee3 + depends: + - __osx >=11.0 + - libbrotlicommon 1.1.0 h5505292_3 + license: MIT + license_family: MIT + purls: [] + size: 29249 + timestamp: 1749230338861 - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.1.0-hb9d3cd8_2.conda sha256: 779f58174e99de3600e939fa46eddb453ec5d3c60bb46cdaa8b4c127224dbf29 md5: 06f70867945ea6a84d35836af780f1de @@ -1862,6 +3126,17 @@ packages: purls: [] size: 281750 timestamp: 1725267679782 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlienc-1.1.0-h5505292_3.conda + sha256: 0734a54db818ddfdfbf388fa53c5036a06bbe17de14005f33215d865d51d8a5e + md5: 1ce5e315293309b5bf6778037375fb08 + depends: + - __osx >=11.0 + - libbrotlicommon 1.1.0 h5505292_3 + license: MIT + license_family: MIT + purls: [] + size: 274404 + timestamp: 1749230355483 - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-31_he106b2a_openblas.conda build_number: 31 sha256: ede8545011f5b208b151fe3e883eb4e31d495ab925ab7b9ce394edca846e0c0d @@ -1877,6 +3152,21 @@ packages: purls: [] size: 16796 timestamp: 1740087984429 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.9.0-34_hb3479ef_openblas.conda + build_number: 34 + sha256: 6639f6c6b2e76cb1be62cd6d9033bda7dc3fab2e5a80f5be4b5c522c27dcba17 + md5: e15018d609b8957c146dcb6c356dd50c + depends: + - libblas 3.9.0 34_h10e41b3_openblas + constrains: + - liblapack 3.9.0 34*_openblas + - blas 2.134 openblas + - liblapacke 3.9.0 34*_openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 19521 + timestamp: 1754678970336 - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp20.1-20.1.4-default_h1df26ce_0.conda sha256: 5c28304eaabc2aaeb47e2ba847ae41e0ad7e2a520a7e19a2c5e846c69b417a5b md5: 96f8d5b2e94c9ba4fef19f1adf068a15 @@ -1934,6 +3224,32 @@ packages: purls: [] size: 438088 timestamp: 1743601695669 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.14.1-h73640d1_0.conda + sha256: 0055b68137309db41ec34c938d95aec71d1f81bd9d998d5be18f32320c3ccba0 + md5: 1af57c823803941dfc97305248a56d57 + depends: + - __osx >=11.0 + - krb5 >=1.21.3,<1.22.0a0 + - libnghttp2 >=1.64.0,<2.0a0 + - libssh2 >=1.11.1,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.0,<4.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: curl + license_family: MIT + purls: [] + size: 403456 + timestamp: 1749033320430 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-20.1.8-hf598326_1.conda + sha256: 119b3ac75cb1ea29981e5053c2cb10d5f0b06fcc81b486cb7281f160daf673a1 + md5: a69ef3239d3268ef8602c7a7823fd982 + depends: + - __osx >=11.0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 568267 + timestamp: 1752814881595 - conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.23-h86f0d12_0.conda sha256: 4db2f70a1441317d964e84c268e388110ad9cf75ca98994d1336d670e62e6f07 md5: 27fe770decaf469a53f3e3a6d593067f @@ -1945,6 +3261,16 @@ packages: purls: [] size: 72783 timestamp: 1745260463421 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libdeflate-1.24-h5773f1b_0.conda + sha256: 417d52b19c679e1881cce3f01cad3a2d542098fa2d6df5485aac40f01aede4d1 + md5: 3baf58a5a87e7c2f4d243ce2f8f2fe5c + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 54790 + timestamp: 1747040549847 - conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.125-hb9d3cd8_0.conda sha256: f53458db897b93b4a81a6dbfd7915ed8fa4a54951f97c698dde6faa028aadfd2 md5: 4c0ab57463117fbb8df85268415082f5 @@ -1970,6 +3296,18 @@ packages: purls: [] size: 134676 timestamp: 1738479519902 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda + sha256: 66aa216a403de0bb0c1340a88d1a06adaff66bae2cfd196731aa24db9859d631 + md5: 44083d2d2c2025afca315c7a172eab2b + depends: + - ncurses + - __osx >=11.0 + - ncurses >=6.5,<7.0a0 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 107691 + timestamp: 1738479560845 - conda: https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_2.conda sha256: 7fd5408d359d05a969133e47af580183fbf38e2235b562193d427bb9dad79723 md5: c151d5eb730e9b7480e6d48c0fc44048 @@ -1990,6 +3328,14 @@ packages: purls: [] size: 112766 timestamp: 1702146165126 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libev-4.33-h93a5062_2.conda + sha256: 95cecb3902fbe0399c3a7e67a5bed1db813e5ab0e22f4023a5e0f722f2cc214f + md5: 36d33e440c31857372a72137f78bacf5 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 107458 + timestamp: 1702146414478 - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.0-h5888daf_0.conda sha256: 33ab03438aee65d6aa667cf7d90c91e5e7d734c19a67aa4c7040742c0a13d505 md5: db0bfbe7dd197b68ad5f30333bae6ce0 @@ -2003,6 +3349,18 @@ packages: purls: [] size: 74427 timestamp: 1743431794976 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.7.1-hec049ff_0.conda + sha256: 8fbb17a56f51e7113ed511c5787e0dec0d4b10ef9df921c4fd1cccca0458f648 + md5: b1ca5f21335782f71a8bd69bdc093f67 + depends: + - __osx >=11.0 + constrains: + - expat 2.7.1.* + license: MIT + license_family: MIT + purls: [] + size: 65971 + timestamp: 1752719657566 - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.6-h2dba641_1.conda sha256: 764432d32db45466e87f10621db5b74363a9f847d2b8b1f9743746cd160f06ab md5: ede4673863426c0883c0063d853bbd85 @@ -2014,6 +3372,16 @@ packages: purls: [] size: 57433 timestamp: 1743434498161 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.6-h1da3d7d_1.conda + sha256: c6a530924a9b14e193ea9adfe92843de2a806d1b7dbfd341546ece9653129e60 + md5: c215a60c2935b517dcda8cad4705734d + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 39839 + timestamp: 1743434670405 - conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.13.3-ha770c72_1.conda sha256: 7be9b3dac469fe3c6146ff24398b685804dfc7a1de37607b84abd076f57cc115 md5: 51f5be229d83ecd401fb369ab96ae669 @@ -2023,6 +3391,15 @@ packages: purls: [] size: 7693 timestamp: 1745369988361 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libfreetype-2.13.3-hce30654_1.conda + sha256: 1f8c16703fe333cdc2639f7cdaf677ac2120843453222944a7c6c85ec342903c + md5: d06282e08e55b752627a707d58779b8f + depends: + - libfreetype6 >=2.13.3 + license: GPL-2.0-only OR FTL + purls: [] + size: 7813 + timestamp: 1745370144506 - conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.13.3-h48d6fc4_1.conda sha256: 7759bd5c31efe5fbc36a7a1f8ca5244c2eabdbeb8fc1bee4b99cf989f35c7d81 md5: 3c255be50a506c50765a93a6644f32fe @@ -2037,6 +3414,19 @@ packages: purls: [] size: 380134 timestamp: 1745369987697 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libfreetype6-2.13.3-h1d14073_1.conda + sha256: c278df049b1a071841aa0aca140a338d087ea594e07dcf8a871d2cfe0e330e75 + md5: b163d446c55872ef60530231879908b9 + depends: + - __osx >=11.0 + - libpng >=1.6.47,<1.7.0a0 + - libzlib >=1.3.1,<2.0a0 + constrains: + - freetype >=2.13.3 + license: GPL-2.0-only OR FTL + purls: [] + size: 333529 + timestamp: 1745370142848 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h767d61c_2.conda sha256: 3a572d031cb86deb541d15c1875aaa097baefc0c580b54dc61f5edab99215792 md5: ef504d1acbd74b7cc6849ef8af47dd03 @@ -2073,6 +3463,16 @@ packages: purls: [] size: 53733 timestamp: 1740240690977 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.1.0-hfdf1602_0.conda + sha256: 9620b4ac9d32fe7eade02081cd60d6a359a927d42bb8e121bd16489acd3c4d8c + md5: e3b7dca2c631782ca1317a994dfe19ec + depends: + - libgfortran5 15.1.0 hb74de2c_0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 133859 + timestamp: 1750183546047 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.2.0-hf1ad2bd_2.conda sha256: c17b7cf3073a1f4e1f34d50872934fa326346e104d3c445abc1e62481ad6085c md5: 556a4fdfac7287d349b8f09aba899693 @@ -2086,6 +3486,18 @@ packages: purls: [] size: 1461978 timestamp: 1740240671964 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.1.0-hb74de2c_0.conda + sha256: 44b8ce4536cc9a0e59c09ff404ef1b0120d6a91afc32799331d85268cbe42438 + md5: 8b158ccccd67a40218e12626a39065a1 + depends: + - llvm-openmp >=8.0.0 + constrains: + - libgfortran 15.1.0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 758352 + timestamp: 1750182604206 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_2.conda sha256: dc2752241fa3d9e40ce552c1942d0a4b5eeb93740c9723873f6fcf8d39ef8d2d md5: 928b8be80851f5d8ffb016f9c81dae7a @@ -2113,6 +3525,22 @@ packages: purls: [] size: 3947789 timestamp: 1743773764878 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libglib-2.84.3-h587fa63_0.conda + sha256: a30510a18f0b85a036f99c744750611b5f26b972cfa70cc9f130b9f42e5bbc18 + md5: bb98995c244b6038892fd59a694a93ed + depends: + - __osx >=11.0 + - libffi >=3.4.6,<3.5.0a0 + - libiconv >=1.18,<2.0a0 + - libintl >=0.25.1,<1.0a0 + - libzlib >=1.3.1,<2.0a0 + - pcre2 >=10.45,<10.46.0a0 + constrains: + - glib 2.84.3 *_0 + license: LGPL-2.1-or-later + purls: [] + size: 3661135 + timestamp: 1754315631978 - conda: https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda sha256: 1175f8a7a0c68b7f81962699751bb6574e6f07db4c9f72825f978e3016f46850 md5: 434ca7e50e40f4918ab701e3facd59a0 @@ -2153,6 +3581,25 @@ packages: purls: [] size: 713084 timestamp: 1740128065462 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.18-h23cfdf5_2.conda + sha256: de0336e800b2af9a40bdd694b03870ac4a848161b35c8a2325704f123f185f03 + md5: 4d5a7445f0b25b6a3ddbb56e790f5251 + depends: + - __osx >=11.0 + license: LGPL-2.1-only + purls: [] + size: 750379 + timestamp: 1754909073836 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libintl-0.25.1-h493aca8_0.conda + sha256: 99d2cebcd8f84961b86784451b010f5f0a795ed1c08f1e7c76fbb3c22abf021a + md5: 5103f6a6b210a3912faf8d7db516918c + depends: + - __osx >=11.0 + - libiconv >=1.18,<2.0a0 + license: LGPL-2.1-or-later + purls: [] + size: 90957 + timestamp: 1751558394144 - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.0-hb9d3cd8_0.conda sha256: 98b399287e27768bf79d48faba8a99a2289748c65cd342ca21033fab1860d4a4 md5: 9fa334557db9f63da6c9285fd2a48638 @@ -2165,6 +3612,17 @@ packages: purls: [] size: 628947 timestamp: 1745268527144 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libjpeg-turbo-3.1.0-h5505292_0.conda + sha256: 78df2574fa6aa5b6f5fc367c03192f8ddf8e27dc23641468d54e031ff560b9d4 + md5: 01caa4fbcaf0e6b08b3aef1151e91745 + depends: + - __osx >=11.0 + constrains: + - jpeg <0.0.0a + license: IJG AND BSD-3-Clause AND Zlib + purls: [] + size: 553624 + timestamp: 1745268405713 - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-31_h7ac8fdf_openblas.conda build_number: 31 sha256: f583661921456e798aba10972a8abbd9d33571c655c1f66eff450edc9cbefcf3 @@ -2180,6 +3638,21 @@ packages: purls: [] size: 16790 timestamp: 1740087997375 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.9.0-34_hc9a63f6_openblas.conda + build_number: 34 + sha256: 659c7cc2d7104c5fa33482d28a6ce085fd116ff5625a117b7dd45a3521bf8efc + md5: 94b13d05122e301de02842d021eea5fb + depends: + - libblas 3.9.0 34_h10e41b3_openblas + constrains: + - libcblas 3.9.0 34*_openblas + - blas 2.134 openblas + - liblapacke 3.9.0 34*_openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 19532 + timestamp: 1754678979401 - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm20-20.1.4-he9d0ab4_0.conda sha256: 56a375dc36df1a4e2061e30ebbacbc9599a11277422a9a3145fd228f772bab53 md5: 96c33bbd084ef2b2463503fb7f1482ae @@ -2205,6 +3678,17 @@ packages: purls: [] size: 111357 timestamp: 1738525339684 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.1-h39f12f2_2.conda + sha256: 0cb92a9e026e7bd4842f410a5c5c665c89b2eb97794ffddba519a626b8ce7285 + md5: d6df911d4564d77c4374b02552cb17d1 + depends: + - __osx >=11.0 + constrains: + - xz 5.8.1.* + license: 0BSD + purls: [] + size: 92286 + timestamp: 1749230283517 - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.64.0-h161d5f1_0.conda sha256: b0f2b3695b13a989f75d8fd7f4778e1c7aabe3b36db83f0fe80b2cd812c0e975 md5: 19e57602824042dfd0446292ef90488b @@ -2222,6 +3706,22 @@ packages: purls: [] size: 647599 timestamp: 1729571887612 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.64.0-h6d7220d_0.conda + sha256: 00cc685824f39f51be5233b54e19f45abd60de5d8847f1a56906f8936648b72f + md5: 3408c02539cee5f1141f9f11450b6a51 + depends: + - __osx >=11.0 + - c-ares >=1.34.2,<2.0a0 + - libcxx >=17 + - libev >=4.33,<4.34.0a0 + - libev >=4.33,<5.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.3.2,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 566719 + timestamp: 1729572385640 - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda sha256: 26d77a3bb4dceeedc2a41bd688564fe71bf2d149fdcf117049970bc02ff1add6 md5: 30fd6e37fe21f86f4bd26d6ee73eeec7 @@ -2257,6 +3757,21 @@ packages: purls: [] size: 5919288 timestamp: 1739825731827 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.30-openmp_h60d53f8_1.conda + sha256: dfa2e506dcbd2b8e5656333021dbd422d2c1655dcfecbd7a50cac9d223c802b4 + md5: 165b15df4e15aba3a2b63897d6e4c539 + depends: + - __osx >=11.0 + - libgfortran + - libgfortran5 >=14.3.0 + - llvm-openmp >=19.1.7 + constrains: + - openblas >=0.3.30,<0.3.31.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 4282228 + timestamp: 1753404509306 - conda: https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_2.conda sha256: 215086c108d80349e96051ad14131b751d17af3ed2cb5a34edd62fa89bfe8ead md5: 7df50d44d4a14d6c31a2c54f2cd92157 @@ -2289,6 +3804,16 @@ packages: purls: [] size: 317390 timestamp: 1753879899951 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libpng-1.6.50-h280e0eb_1.conda + sha256: a2e0240fb0c79668047b528976872307ea80cb330baf8bf6624ac2c6443449df + md5: 4d0f5ce02033286551a32208a5519884 + depends: + - __osx >=11.0 + - libzlib >=1.3.1,<2.0a0 + license: zlib-acknowledgement + purls: [] + size: 287056 + timestamp: 1753879907258 - conda: https://conda.anaconda.org/conda-forge/linux-64/libpq-17.4-h27ae623_1.conda sha256: ba2fd74be9d8c38489b9c6c18fa2fa87437dac76dfe285f86425c1b815e59fa2 md5: 37fba334855ef3b51549308e61ed7a3d @@ -2314,6 +3839,17 @@ packages: purls: [] size: 918664 timestamp: 1742083674731 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.50.4-h4237e3c_0.conda + sha256: 802ebe62e6bc59fc26b26276b793e0542cfff2d03c086440aeaf72fb8bbcec44 + md5: 1dcb0468f5146e38fae99aef9656034b + depends: + - __osx >=11.0 + - icu >=75.1,<76.0a0 + - libzlib >=1.3.1,<2.0a0 + license: blessing + purls: [] + size: 902645 + timestamp: 1753948599139 - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hf672d98_0.conda sha256: 0407ac9fda2bb67e11e357066eff144c845801d00b5f664efbc48813af1e7bb9 md5: be2de152d8073ef1c01b7728475f2fe7 @@ -2327,6 +3863,17 @@ packages: purls: [] size: 304278 timestamp: 1732349402869 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda + sha256: 8bfe837221390ffc6f111ecca24fa12d4a6325da0c8d131333d63d6c37f27e0a + md5: b68e8f66b94b44aaa8de4583d3d4cc40 + depends: + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.0,<4.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 279193 + timestamp: 1745608793272 - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-14.2.0-h8f9b012_2.conda sha256: 8f5bd92e4a24e1d35ba015c5252e8f818898478cb3bc50bd8b12ab54707dc4da md5: a78c856b6dc6bf4ea8daeb9beaaa3fb0 @@ -2366,6 +3913,23 @@ packages: purls: [] size: 428173 timestamp: 1734398813264 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libtiff-4.7.0-h025e3ab_6.conda + sha256: d6ed4b307dde5d66b73aa3f155b3ed40ba9394947cfe148e2cd07605ef4b410b + md5: d0862034c2c563ef1f52a3237c133d8d + depends: + - __osx >=11.0 + - lerc >=4.0.0,<5.0a0 + - libcxx >=19 + - libdeflate >=1.24,<1.25.0a0 + - libjpeg-turbo >=3.1.0,<4.0a0 + - liblzma >=5.8.1,<6.0a0 + - libwebp-base >=1.6.0,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: HPND + purls: [] + size: 372136 + timestamp: 1755012109767 - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda sha256: 787eb542f055a2b3de553614b25f09eefb0a0931b0c87dbcce6efdfd92f04f18 md5: 40b61aab5c7ba9ff276c41cfffe6b80b @@ -2387,6 +3951,16 @@ packages: purls: [] size: 891272 timestamp: 1737016632446 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.51.0-h6caf38d_1.conda + sha256: 042c7488ad97a5629ec0a991a8b2a3345599401ecc75ad6a5af73b60e6db9689 + md5: c0d87c3c8e075daf1daf6c31b53e8083 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 421195 + timestamp: 1753948426421 - conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda sha256: 3aed21ab28eddffdaf7f804f49be7a7d701e8f0e46c856d801270b470820a37b md5: aea31d2e5b1091feca96fcfe945c3cf9 @@ -2400,6 +3974,18 @@ packages: purls: [] size: 429011 timestamp: 1752159441324 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libwebp-base-1.6.0-h07db88b_0.conda + sha256: a4de3f371bb7ada325e1f27a4ef7bcc81b2b6a330e46fac9c2f78ac0755ea3dd + md5: e5e7d467f80da752be17796b87fe6385 + depends: + - __osx >=11.0 + constrains: + - libwebp 1.6.0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 294974 + timestamp: 1752159906788 - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda sha256: 666c0c431b23c6cec6e492840b176dde533d48b7e6fb8883f5071223433776aa md5: 92ed62436b625154323d40d5f2f11dd7 @@ -2414,6 +4000,19 @@ packages: purls: [] size: 395888 timestamp: 1727278577118 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxcb-1.17.0-hdb1d25a_0.conda + sha256: bd3816218924b1e43b275863e21a3e13a5db4a6da74cca8e60bc3c213eb62f71 + md5: af523aae2eca6dfa1c8eec693f5b9a79 + depends: + - __osx >=11.0 + - pthread-stubs + - xorg-libxau >=1.0.11,<2.0a0 + - xorg-libxdmcp + license: MIT + license_family: MIT + purls: [] + size: 323658 + timestamp: 1727278733917 - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda sha256: 6ae68e0b86423ef188196fff6207ed0c8195dd84273cb5623b85aa08033a410c md5: 5aa797f8787fe7a17d1b0821485b5adc @@ -2478,6 +4077,31 @@ packages: purls: [] size: 60963 timestamp: 1727963148474 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda + sha256: ce34669eadaba351cd54910743e6a2261b67009624dbc7daeeafdef93616711b + md5: 369964e85dc26bfe78f41399b366c435 + depends: + - __osx >=11.0 + constrains: + - zlib 1.3.1 *_2 + license: Zlib + license_family: Other + purls: [] + size: 46438 + timestamp: 1727963202283 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-20.1.8-hbb9b287_1.conda + sha256: e56f46b253dd1a99cc01dde038daba7789fc6ed35b2a93e3fc44b8578a82b3ec + md5: a10bdc3e5d9e4c1ce554c83855dff6c4 + depends: + - __osx >=11.0 + constrains: + - openmp 20.1.8|20.1.8.* + - intel-openmp <0.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + purls: [] + size: 283300 + timestamp: 1753978829840 - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-3.0.0-pyhd8ed1ab_1.conda sha256: 0fbacdfb31e55964152b24d5567e9a9996e1e7902fb08eb7d91b5fd6ce60803a md5: fee3164ac23dfca50cfcc8b85ddefb81 @@ -2490,6 +4114,23 @@ packages: - pkg:pypi/markdown-it-py?source=hash-mapping size: 64430 timestamp: 1733250550053 +- conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda + sha256: 7b1da4b5c40385791dbc3cc85ceea9fad5da680a27d5d3cb8bfaa185e304a89e + md5: 5b5203189eb668f042ac2b0826244964 + depends: + - mdurl >=0.1,<1 + - python >=3.10 + license: MIT + license_family: MIT + purls: + - pkg:pypi/markdown-it-py?source=compressed-mapping + size: 64736 + timestamp: 1754951288511 +- pypi: https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl + name: markupsafe + version: 3.0.2 + sha256: 846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225 + requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl name: markupsafe version: 3.0.2 @@ -2510,6 +4151,20 @@ packages: - pkg:pypi/matplotlib?source=compressed-mapping size: 17348 timestamp: 1754005897072 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/matplotlib-3.10.5-py312h1f38498_0.conda + sha256: e75ed12886976f48e938ccd3afcc41165904589133b03e4e0f1c1ddd6ff3a071 + md5: 92933847a00ad390bc9fe99c50c73b3f + depends: + - matplotlib-base >=3.10.5,<3.10.6.0a0 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + - tornado >=5 + license: PSF-2.0 + license_family: PSF + purls: + - pkg:pypi/matplotlib?source=compressed-mapping + size: 17451 + timestamp: 1754005874746 - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.5-py312he3d6523_0.conda sha256: 66e94e6226fd3dd04bb89d04079e2d8e2c74d923c0bbf255e483f127aee621ff md5: 9246288e5ef2a944f7c9c648f9f331c7 @@ -2540,6 +4195,35 @@ packages: - pkg:pypi/matplotlib?source=compressed-mapping size: 8071030 timestamp: 1754005868258 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/matplotlib-base-3.10.5-py312h05635fa_0.conda + sha256: bc44413a9f1984e6ab39bd0b805430a4e11e41e1d0389254c4d2d056be610512 + md5: 96e5de8c96b4557430f6af0d6693d4c9 + depends: + - __osx >=11.0 + - contourpy >=1.0.1 + - cycler >=0.10 + - fonttools >=4.22.0 + - freetype + - kiwisolver >=1.3.1 + - libcxx >=19 + - libfreetype >=2.13.3 + - libfreetype6 >=2.13.3 + - numpy >=1.23 + - numpy >=1.23,<3 + - packaging >=20.0 + - pillow >=8 + - pyparsing >=2.3.1 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python-dateutil >=2.7 + - python_abi 3.12.* *_cp312 + - qhull >=2020.2,<2020.3.0a0 + license: PSF-2.0 + license_family: PSF + purls: + - pkg:pypi/matplotlib?source=compressed-mapping + size: 8031746 + timestamp: 1754005848626 - pypi: https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl name: matplotlib-inline version: 0.1.7 @@ -2569,6 +4253,17 @@ packages: - pkg:pypi/more-itertools?source=hash-mapping size: 58739 timestamp: 1736883940984 +- conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.7.0-pyhd8ed1ab_0.conda + sha256: d0c2253dcb1da6c235797b57d29de688dabc2e48cc49645b1cff2b52b7907428 + md5: 7c65a443d58beb0518c35b26c70e201d + depends: + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/more-itertools?source=hash-mapping + size: 61359 + timestamp: 1745349566387 - pypi: https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl name: mpmath version: 1.3.0 @@ -2587,6 +4282,11 @@ packages: version: 1.1.0 sha256: 17fb65dd0bec285907f68b15734a993ad3fc94332b5bb21b0435846228de1f39 requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/ab/65/7d1de38c8a22cf8b1551469159d4b6cf49be2126adc2482de50976084d78/msgpack-1.1.1-cp312-cp312-macosx_11_0_arm64.whl + name: msgpack + version: 1.1.1 + sha256: 33be9ab121df9b6b461ff91baac6f2731f83d9b27ed948c5b9d1978ae28bf157 + requires_python: '>=3.8' - pypi: https://files.pythonhosted.org/packages/9b/5d/f25ac7d4fb77cbd53ddc6d05d833c6bf52b12770a44fa9a447eed470ca9a/msgpack_numpy-0.4.8-py2.py3-none-any.whl name: msgpack-numpy version: 0.4.8 @@ -2644,6 +4344,15 @@ packages: purls: [] size: 891641 timestamp: 1738195959188 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda + sha256: 2827ada40e8d9ca69a153a45f7fd14f32b2ead7045d3bbb5d10964898fe65733 + md5: 068d497125e4bf8a66bf707254fff5ae + depends: + - __osx >=11.0 + license: X11 AND BSD-3-Clause + purls: [] + size: 797030 + timestamp: 1738196177597 - pypi: https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl name: networkx version: 3.4.2 @@ -2679,6 +4388,42 @@ packages: - pytest>=7.2 ; extra == 'test' - pytest-cov>=4.0 ; extra == 'test' requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/eb/8d/776adee7bbf76365fdd7f2552710282c79a4ead5d2a46408c9043a2b70ba/networkx-3.5-py3-none-any.whl + name: networkx + version: '3.5' + sha256: 0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec + requires_dist: + - numpy>=1.25 ; extra == 'default' + - scipy>=1.11.2 ; extra == 'default' + - matplotlib>=3.8 ; extra == 'default' + - pandas>=2.0 ; extra == 'default' + - pre-commit>=4.1 ; extra == 'developer' + - mypy>=1.15 ; extra == 'developer' + - sphinx>=8.0 ; extra == 'doc' + - pydata-sphinx-theme>=0.16 ; extra == 'doc' + - sphinx-gallery>=0.18 ; extra == 'doc' + - numpydoc>=1.8.0 ; extra == 'doc' + - pillow>=10 ; extra == 'doc' + - texext>=0.6.7 ; extra == 'doc' + - myst-nb>=1.1 ; extra == 'doc' + - intersphinx-registry ; extra == 'doc' + - osmnx>=2.0.0 ; extra == 'example' + - momepy>=0.7.2 ; extra == 'example' + - contextily>=1.6 ; extra == 'example' + - seaborn>=0.13 ; extra == 'example' + - cairocffi>=1.7 ; extra == 'example' + - igraph>=0.11 ; extra == 'example' + - scikit-learn>=1.5 ; extra == 'example' + - lxml>=4.6 ; extra == 'extra' + - pygraphviz>=1.14 ; extra == 'extra' + - pydot>=3.0.1 ; extra == 'extra' + - sympy>=1.10 ; extra == 'extra' + - pytest>=7.2 ; extra == 'test' + - pytest-cov>=4.0 ; extra == 'test' + - pytest-xdist>=3.0 ; extra == 'test' + - pytest-mpl ; extra == 'test-extras' + - pytest-randomly ; extra == 'test-extras' + requires_python: '>=3.11' - conda: https://conda.anaconda.org/conda-forge/linux-64/nh3-0.2.21-py39h77e2912_1.conda noarch: python sha256: 05b2fcbc831ea2936108ba1ebdb249d310d710c7880a98a25817510cf8a41d2a @@ -2697,6 +4442,23 @@ packages: - pkg:pypi/nh3?source=hash-mapping size: 621078 timestamp: 1741652643562 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/nh3-0.3.0-py39h24c5d98_0.conda + noarch: python + sha256: bc135c9abf5b38a63abc082712af64942663f2e5373f535df52ba6fec7988a24 + md5: 12896e493335f2f37257ed070d8a4080 + depends: + - python + - __osx >=11.0 + - _python_abi3_support 1.* + - cpython >=3.9 + constrains: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/nh3?source=hash-mapping + size: 624089 + timestamp: 1752853325963 - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.9.1-pyhd8ed1ab_1.conda sha256: 3636eec0e60466a00069b47ce94b6d88b01419b6577d8e393da44bb5bc8d3468 md5: 7ba3f09fceae6a120d664217e58fe686 @@ -2709,6 +4471,38 @@ packages: - pkg:pypi/nodeenv?source=hash-mapping size: 34574 timestamp: 1734112236147 +- conda: https://conda.anaconda.org/conda-forge/linux-64/nodejs-22.13.0-hf235a45_0.conda + sha256: 925ea8839d6f26d0eb4204675b98a862803a9a9657fd36a4a22c4c29a479a911 + md5: 1f9efd96347aa008bd2c735d7d88fc75 + depends: + - __glibc >=2.28,<3.0.a0 + - icu >=75.1,<76.0a0 + - libgcc >=13 + - libstdcxx >=13 + - libuv >=1.50.0,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.4.1,<4.0a0 + - zlib + license: MIT + license_family: MIT + purls: [] + size: 21691794 + timestamp: 1741809786920 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/nodejs-24.4.1-hab9d20b_0.conda + sha256: c79d2c81f80a9adedc77362f2e8b10879ed0f9806deb6ba2464c1287a05f0b9b + md5: 463a537de602f8558604f27395b323d0 + depends: + - libcxx >=19 + - __osx >=11.0 + - openssl >=3.5.1,<4.0a0 + - libuv >=1.51.0,<2.0a0 + - icu >=75.1,<76.0a0 + - libzlib >=1.3.1,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 17949155 + timestamp: 1752839389217 - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.3.2-py312h33ff503_0.conda sha256: d54e52df67e0be7e5faa9e6f0efccea3d72f635a3159cc151c4668e5159f6ef3 md5: 3f6efbc40eb13f019c856c410fa921d2 @@ -2730,6 +4524,26 @@ packages: - pkg:pypi/numpy?source=compressed-mapping size: 8785045 timestamp: 1753401550884 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.3.2-py312h2f38b44_0.conda + sha256: 581039072c18b2abd8dfcf7fe5c16a8fbb72e14821bad4817ca00dbb16f3bad3 + md5: c58a6fa1ee8edb9de10d0f5c91806193 + depends: + - python + - libcxx >=19 + - python 3.12.* *_cpython + - __osx >=11.0 + - liblapack >=3.9.0,<4.0a0 + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - python_abi 3.12.* *_cp312 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/numpy?source=hash-mapping + size: 6657726 + timestamp: 1753401542508 - pypi: https://files.pythonhosted.org/packages/ae/71/1c91302526c45ab494c23f61c7a84aa568b8c1f9d196efa5993957faf906/nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_x86_64.whl name: nvidia-cublas-cu12 version: 12.4.5.8 @@ -2817,6 +4631,20 @@ packages: purls: [] size: 357828 timestamp: 1754297886899 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.3-h889cd5d_1.conda + sha256: 6013916893fcd9bc97c479279cfe4616de7735ec566bad0ee41bc729e14d31b2 + md5: ab581998c77c512d455a13befcddaac3 + depends: + - __osx >=11.0 + - libcxx >=19 + - libpng >=1.6.50,<1.7.0a0 + - libtiff >=4.7.0,<4.8.0a0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 320198 + timestamp: 1754297986425 - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.9-he970967_0.conda sha256: 224f458848f792fe9e3587ee6b626d4eaad63aead0e5e6c25cbe29aba7b05c53 md5: ca2de8bbdc871bce41dbf59e51324165 @@ -2844,6 +4672,17 @@ packages: purls: [] size: 2939306 timestamp: 1739301879343 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.5.2-he92f556_0.conda + sha256: f6d1c87dbcf7b39fad24347570166dade1c533ae2d53c60a70fa4dc874ef0056 + md5: bcb0d87dfbc199d0a461d2c7ca30b3d8 + depends: + - __osx >=11.0 + - ca-certificates + license: Apache-2.0 + license_family: Apache + purls: [] + size: 3074848 + timestamp: 1754465710470 - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.2-pyhd8ed1ab_2.conda sha256: da157b19bcd398b9804c5c52fc000fcb8ab0525bdb9c70f95beaa0bb42f85af1 md5: 3bfed7e6228ebf2f7b9eaa47f1b4e2aa @@ -2855,6 +4694,18 @@ packages: - pkg:pypi/packaging?source=hash-mapping size: 60164 timestamp: 1733203368787 +- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda + sha256: 289861ed0c13a15d7bbb408796af4de72c2fe67e2bcb0de98f4c3fce259d7991 + md5: 58335b26c38bf4a20f399384c33cbcf9 + depends: + - python >=3.8 + - python + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/packaging?source=hash-mapping + size: 62477 + timestamp: 1745345660407 - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-2.3.1-py312hf79963d_0.conda sha256: 6ec86b1da8432059707114270b9a45d767dac97c4910ba82b1f4fa6f74e077c8 md5: 7c73e62e62e5864b8418440e2a2cc246 @@ -2907,6 +4758,58 @@ packages: - pkg:pypi/pandas?source=hash-mapping size: 15092371 timestamp: 1752082221274 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-2.3.1-py312h98f7732_0.conda + sha256: f4f98436dde01309935102de2ded045bb5500b42fb30a3bf8751b15affee4242 + md5: d3775e9b27579a0e96150ce28a2542bd + depends: + - __osx >=11.0 + - libcxx >=19 + - numpy >=1.22.4 + - numpy >=1.23,<3 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python-dateutil >=2.8.2 + - python-tzdata >=2022.7 + - python_abi 3.12.* *_cp312 + - pytz >=2020.1 + constrains: + - openpyxl >=3.1.0 + - pyarrow >=10.0.1 + - s3fs >=2022.11.0 + - zstandard >=0.19.0 + - psycopg2 >=2.9.6 + - fastparquet >=2022.12.0 + - fsspec >=2022.11.0 + - qtpy >=2.3.0 + - blosc >=1.21.3 + - xlsxwriter >=3.0.5 + - xarray >=2022.12.0 + - python-calamine >=0.1.7 + - tabulate >=0.9.0 + - odfpy >=1.4.1 + - numexpr >=2.8.4 + - tzdata >=2022.7 + - scipy >=1.10.0 + - pyreadstat >=1.2.0 + - beautifulsoup4 >=4.11.2 + - numba >=0.56.4 + - pyqt5 >=5.15.9 + - pytables >=3.8.0 + - lxml >=4.9.2 + - xlrd >=2.0.1 + - matplotlib >=3.6.3 + - bottleneck >=1.3.6 + - pandas-gbq >=0.19.0 + - html5lib >=1.1 + - pyxlsb >=1.0.10 + - sqlalchemy >=2.0.0 + - gcsfs >=2022.11.0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/pandas?source=hash-mapping + size: 13991815 + timestamp: 1752082557265 - pypi: https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl name: parso version: 0.8.4 @@ -2943,6 +4846,18 @@ packages: purls: [] size: 952308 timestamp: 1723488734144 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pcre2-10.45-ha881caa_0.conda + sha256: e9ecb706b58b5a2047c077b3a1470e8554f3aad02e9c3c00cfa35d537420fea3 + md5: a52385b93558d8e6bbaeec5d61a21cd7 + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 837826 + timestamp: 1745955207242 - pypi: https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl name: pexpect version: 4.9.0 @@ -2972,6 +4887,29 @@ packages: - pkg:pypi/pillow?source=hash-mapping size: 42964111 timestamp: 1751482158083 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pillow-11.3.0-py312h50aef2c_0.conda + sha256: 3d60288e8cfd42e4548c9e5192a285e73f81df2869f69b9d3905849b45d9bd2a + md5: dddff48655b5cd24a5170a6df979943a + depends: + - __osx >=11.0 + - lcms2 >=2.17,<3.0a0 + - libfreetype >=2.13.3 + - libfreetype6 >=2.13.3 + - libjpeg-turbo >=3.1.0,<4.0a0 + - libtiff >=4.7.0,<4.8.0a0 + - libwebp-base >=1.5.0,<2.0a0 + - libxcb >=1.17.0,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - openjpeg >=2.5.3,<3.0a0 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + - tk >=8.6.13,<8.7.0a0 + license: HPND + purls: + - pkg:pypi/pillow?source=hash-mapping + size: 42514714 + timestamp: 1751482419501 - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.0.1-pyh8b19718_0.conda sha256: 585940f09d87787f79f73ff5dff8eb2af8a67e5bec5eebf2f553cd26c840ba69 md5: 79b5c1440aedc5010f687048d9103628 @@ -2985,6 +4923,19 @@ packages: - pkg:pypi/pip?source=hash-mapping size: 1256460 timestamp: 1739142857253 +- conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh8b19718_0.conda + sha256: ec9ed3cef137679f3e3a68e286c6efd52144684e1be0b05004d9699882dadcdd + md5: dfce4b2af4bfe90cdcaf56ca0b28ddf5 + depends: + - python >=3.9,<3.13.0a0 + - setuptools + - wheel + license: MIT + license_family: MIT + purls: + - pkg:pypi/pip?source=compressed-mapping + size: 1177168 + timestamp: 1753924973872 - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h537e5f6_0.conda sha256: f1a4bed536f8860b4e67fcd17662884dfa364e515c195c6d2e41dbf70f19263b md5: b0674781beef9e302a17c330213ec41a @@ -3008,6 +4959,18 @@ packages: purls: [] size: 115175 timestamp: 1720805894943 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pkg-config-0.29.2-hde07d2e_1009.conda + sha256: d82f4655b2d67fe12eefe1a3eea4cd27d33fa41dbc5e9aeab5fd6d3d2c26f18a + md5: b4f41e19a8c20184eec3aaf0f0953293 + depends: + - __osx >=11.0 + - libglib >=2.80.3,<3.0a0 + - libiconv >=1.17,<2.0a0 + license: GPL-2.0-or-later + license_family: GPL + purls: [] + size: 49724 + timestamp: 1720806128118 - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.3.8-pyhe01879c_0.conda sha256: 0f48999a28019c329cd3f6fd2f01f09fc32cc832f7d6bbe38087ddac858feaa3 md5: 424844562f5d337077b445ec6b1398a7 @@ -3047,6 +5010,22 @@ packages: - pkg:pypi/pre-commit?source=hash-mapping size: 195854 timestamp: 1742475656293 +- conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.3.0-pyha770c72_0.conda + sha256: 66b6d429ab2201abaa7282af06b17f7631dcaafbc5aff112922b48544514b80a + md5: bc6c44af2a9e6067dd7e949ef10cdfba + depends: + - cfgv >=2.0.0 + - identify >=1.0.0 + - nodeenv >=0.11.1 + - python >=3.9 + - pyyaml >=5.1 + - virtualenv >=20.10.0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pre-commit?source=hash-mapping + size: 195839 + timestamp: 1754831350570 - pypi: https://files.pythonhosted.org/packages/e4/ea/d836f008d33151c7a1f62caf3d8dd782e4d15f6a43897f64480c2b8de2ad/prompt_toolkit-3.0.50-py3-none-any.whl name: prompt-toolkit version: 3.0.50 @@ -3054,6 +5033,13 @@ packages: requires_dist: - wcwidth requires_python: '>=3.8.0' +- pypi: https://files.pythonhosted.org/packages/ce/4f/5249960887b1fbe561d9ff265496d170b55a735b76724f10ef19f9e40716/prompt_toolkit-3.0.51-py3-none-any.whl + name: prompt-toolkit + version: 3.0.51 + sha256: 52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07 + requires_dist: + - wcwidth + requires_python: '>=3.8' - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda sha256: 9c88f8c64590e9567c6c80823f0328e58d3b1efb0e1c539c0315ceca764e0973 md5: b3c17d95b5a10c6e64a21fa17573e70e @@ -3065,6 +5051,16 @@ packages: purls: [] size: 8252 timestamp: 1726802366959 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pthread-stubs-0.4-hd74edd7_1002.conda + sha256: 8ed65e17fbb0ca944bfb8093b60086e3f9dd678c3448b5de212017394c247ee3 + md5: 415816daf82e0b23a736a069a75e9da7 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 8381 + timestamp: 1726802424786 - pypi: https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl name: ptyprocess version: 0.7.0 @@ -3075,6 +5071,12 @@ packages: sha256: 1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0 requires_dist: - pytest ; extra == 'tests' +- pypi: https://files.pythonhosted.org/packages/a3/17/c476487ba903c7d793db633b4e8ca4a420ae272890302189d9402ba8ff85/py3dmol-2.5.2-py2.py3-none-any.whl + name: py3dmol + version: 2.5.2 + sha256: b921940ff046cf7ca008a249cbd5debec561dcf337f1e5f3df7ac5d4a1954e8e + requires_dist: + - ipython ; extra == 'ipython' - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda sha256: 79db7928d13fab2d892592223d7570f5061c192f27b9febd1a418427b719acc6 md5: 12c566707c80111f9799308d9e265aef @@ -3087,6 +5089,15 @@ packages: - pkg:pypi/pycparser?source=hash-mapping size: 110100 timestamp: 1733195786147 +- pypi: https://files.pythonhosted.org/packages/00/78/9cbcc1c073b9d4918e925af1a059762265dc65004e020511b2a06fbfd020/pydssp-0.9.1-py3-none-any.whl + name: pydssp + version: 0.9.1 + sha256: 74fb8129c07c1625bb687b80f7e94ae7ebf1277725258d7fc75fc1f3d12a67dc + requires_dist: + - numpy + - torch + - einops + - tqdm - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.1-pyhd8ed1ab_0.conda sha256: 28a3e3161390a9d23bc02b4419448f8d27679d9e2c250e29849e37749c8de86b md5: 232fb4577b6687b2d503ef8e254270c9 @@ -3098,6 +5109,21 @@ packages: - pkg:pypi/pygments?source=hash-mapping size: 888600 timestamp: 1736243563082 +- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + sha256: 5577623b9f6685ece2697c6eb7511b4c9ac5fb607c9babc2646c811b428fd46a + md5: 6b6ece66ebcae2d5f326c77ef2c5a066 + depends: + - python >=3.9 + license: BSD-2-Clause + license_family: BSD + purls: + - pkg:pypi/pygments?source=hash-mapping + size: 889287 + timestamp: 1750615908735 +- pypi: https://files.pythonhosted.org/packages/ec/cd/bd196b2cf014afb1009de8b0f05ecd54011d881944e62763f3c1b1e8ef37/pygtrie-2.5.0-py3-none-any.whl + name: pygtrie + version: 2.5.0 + sha256: 8795cda8105493d5ae159a5bef313ff13156c5d4d72feddefacaad59f8c8ce16 - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.3-pyhe01879c_2.conda sha256: afe32182b1090911b64ac0f29eb47e03a015d142833d8a917defd65d91c99b74 md5: aa0028616c0750c773698fdc254b2b8d @@ -3110,6 +5136,40 @@ packages: - pkg:pypi/pyparsing?source=compressed-mapping size: 102292 timestamp: 1753873557076 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pyright-1.1.399-py312h66e93f0_0.conda + sha256: 9857f51927cbe196ce7c0b4258504283a3492025a54dd7396282e718133eada2 + md5: 2fcde1e79f9d16a21acc7a1391c80216 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - nodeenv >=1.6.0 + - nodejs + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + - typing_extensions >=4.1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyright?source=hash-mapping + size: 3543823 + timestamp: 1744274982054 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyright-1.1.399-py312hea69d52_0.conda + sha256: 97a022cd83aaad61b347ba2d420f40f206c92c201b612544f5a16d82542900d8 + md5: 2ec7ce1f1637de2984b9a6d0362d07ec + depends: + - __osx >=11.0 + - nodeenv >=1.6.0 + - nodejs + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + - typing_extensions >=4.1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyright?source=hash-mapping + size: 3572220 + timestamp: 1744275049046 - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.9.0-py312h91f0f75_0.conda sha256: 4db931dccd8347140e79236378096d9a1b97b98bbd206d54cebd42491ad12535 md5: e3a335c7530a1d0c4db621914f00f9f7 @@ -3180,6 +5240,21 @@ packages: - pkg:pypi/pytest-cov?source=hash-mapping size: 28216 timestamp: 1749778064293 +- conda: https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.8.0-pyhd8ed1ab_0.conda + sha256: b7b58a5be090883198411337b99afb6404127809c3d1c9f96e99b59f36177a96 + md5: 8375cfbda7c57fbceeda18229be10417 + depends: + - execnet >=2.1 + - pytest >=7.0.0 + - python >=3.9 + constrains: + - psutil >=3.0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pytest-xdist?source=hash-mapping + size: 39300 + timestamp: 1751452761594 - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.9-h9e4cc4f_1_cpython.conda build_number: 1 sha256: 77f2073889d4c91a57bc0da73a0466d9164dbcf6191ea9c3a7be6872f784d625 @@ -3208,6 +5283,28 @@ packages: purls: [] size: 31670716 timestamp: 1741130026152 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.11-hc22306f_0_cpython.conda + sha256: cde8b944c2dc378a5afbc48028d0843583fd215493d5885a80f1b41de085552f + md5: 9207ebad7cfbe2a4af0702c92fd031c4 + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.7.0,<3.0a0 + - libffi >=3.4.6,<3.5.0a0 + - liblzma >=5.8.1,<6.0a0 + - libsqlite >=3.50.0,<4.0a0 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.0,<4.0a0 + - readline >=8.2,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + constrains: + - python_abi 3.12.* *_cp312 + license: Python-2.0 + purls: [] + size: 13009234 + timestamp: 1749048134449 - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda sha256: d6a17ece93bbd5139e02d2bd7dbfa80bee1a4261dced63f65f679121686bf664 md5: 5b8d21249ff20967101ffa321cab24e8 @@ -3221,6 +5318,16 @@ packages: - pkg:pypi/python-dateutil?source=hash-mapping size: 233310 timestamp: 1751104122689 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.11-hd8ed1ab_0.conda + sha256: b8afeaefe409d61fa4b68513b25a66bb17f3ca430d67cfea51083c7bfbe098ef + md5: 859c6bec94cd74119f12b961aba965a8 + depends: + - cpython 3.12.11.* + - python_abi * *_cp312 + license: Python-2.0 + purls: [] + size: 45836 + timestamp: 1749047798827 - conda: https://conda.anaconda.org/conda-forge/noarch/python-gil-3.12.9-hd8ed1ab_1.conda sha256: d45a5a99ec3ad65d390590905c0d79b6223468d75425d988106473056ddc35e7 md5: a1a3aa64397603a81615400388409e10 @@ -3253,6 +5360,17 @@ packages: purls: [] size: 6872 timestamp: 1743483197238 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-8_cp312.conda + build_number: 8 + sha256: 80677180dd3c22deb7426ca89d6203f1c7f1f256f2d5a94dc210f6e758229809 + md5: c3efd25ac4d74b1584d2f7a57195ddf1 + constrains: + - python 3.12.* *_cpython + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 6958 + timestamp: 1752805918820 - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2025.2-pyhd8ed1ab_0.conda sha256: 8d2a8bf110cc1fc3df6904091dead158ba3e614d8402a83e51ed3a8aa93cdeb0 md5: bc8e3267d44011051f2eb14d22fb0960 @@ -3279,6 +5397,21 @@ packages: - pkg:pypi/pyyaml?source=hash-mapping size: 206903 timestamp: 1737454910324 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyyaml-6.0.2-py312h998013c_2.conda + sha256: ad225ad24bfd60f7719709791345042c3cb32da1692e62bd463b084cf140e00d + md5: 68149ed4d4e9e1c42d2ba1f27f08ca96 + depends: + - __osx >=11.0 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyyaml?source=hash-mapping + size: 192148 + timestamp: 1737454886351 - conda: https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda sha256: 776363493bad83308ba30bcb88c2552632581b143e8ee25b1982c8c743e73abc md5: 353823361b1d27eb3960efb076dfcaf6 @@ -3290,6 +5423,16 @@ packages: purls: [] size: 552937 timestamp: 1720813982144 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/qhull-2020.2-h420ef59_5.conda + sha256: 873ac689484262a51fd79bc6103c1a1bedbf524924d7f0088fb80703042805e4 + md5: 6483b1f59526e05d7d894e466b5b6924 + depends: + - __osx >=11.0 + - libcxx >=16 + license: LicenseRef-Qhull + purls: [] + size: 516376 + timestamp: 1720814307311 - conda: https://conda.anaconda.org/conda-forge/linux-64/qt6-main-6.9.0-h6441bc3_0.conda sha256: 5f04a118f6f4124bf0f3a7b7ca2510954860c764db8c25a62bcfa91f51693073 md5: d3df16592e15a3f833cfc4d19ae58677 @@ -3363,6 +5506,16 @@ packages: purls: [] size: 282480 timestamp: 1740379431762 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h1d1bf99_2.conda + sha256: 7db04684d3904f6151eff8673270922d31da1eea7fa73254d01c437f49702e34 + md5: 63ef3f6e6d6d5c589e64f11263dc5676 + depends: + - ncurses >=6.5,<7.0a0 + license: GPL-3.0-only + license_family: GPL + purls: [] + size: 252359 + timestamp: 1740379663071 - conda: https://conda.anaconda.org/conda-forge/noarch/readme_renderer-44.0-pyhd8ed1ab_1.conda sha256: 66f3adf6aaabf977cfcc22cb65607002b1de4a22bc9fac7be6bb774bc6f85a3a md5: c58dd5d147492671866464405364c0f1 @@ -3383,6 +5536,11 @@ packages: version: 2024.11.6 sha256: 70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/cd/70/69506d53397b4bd6954061bae75677ad34deb7f6ca3ba199660d6f728ff5/regex-2025.7.34-cp312-cp312-macosx_11_0_arm64.whl + name: regex + version: 2025.7.34 + sha256: 0200a5150c4cf61e407038f4b4d5cdad13e86345dac29ff9dab3d75d905cf130 + requires_python: '>=3.9' - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.3-pyhd8ed1ab_1.conda sha256: d701ca1136197aa121bbbe0e8c18db6b5c94acbd041c2b43c70e5ae104e1d8ad md5: a9b9368f3701a417eac9edbcae7cb737 @@ -3398,8 +5556,25 @@ packages: license_family: APACHE purls: - pkg:pypi/requests?source=hash-mapping - size: 58723 - timestamp: 1733217126197 + size: 58723 + timestamp: 1733217126197 +- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.4-pyhd8ed1ab_0.conda + sha256: 9866aaf7a13c6cfbe665ec7b330647a0fb10a81e6f9b8fee33642232a1920e18 + md5: f6082eae112814f1447b56a5e1f6ed05 + depends: + - certifi >=2017.4.17 + - charset-normalizer >=2,<4 + - idna >=2.5,<4 + - python >=3.9 + - urllib3 >=1.21.1,<3 + constrains: + - chardet >=3.0.2,<6 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/requests?source=hash-mapping + size: 59407 + timestamp: 1749498221996 - conda: https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-1.0.0-pyhd8ed1ab_1.conda sha256: c0b815e72bb3f08b67d60d5e02251bbb0164905b5f72942ff5b6d2a339640630 md5: 66de8645e324fda0ea6ef28c2f99a2ab @@ -3434,6 +5609,16 @@ packages: purls: [] size: 186921 timestamp: 1728886721623 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/rhash-1.4.6-h5505292_1.conda + sha256: f4957c05f4fbcd99577de8838ca4b5b1ae4b400a44be647a0159c14f85b9bfc0 + md5: 029e812c8ae4e0d4cf6ff4f7d8dc9366 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 185448 + timestamp: 1748645057503 - conda: https://conda.anaconda.org/conda-forge/noarch/rich-14.0.0-pyh29332c3_0.conda sha256: d10e2b66a557ec6296844e04686db87818b0df87d73c06388f2332fda3f7d2d5 md5: 202f08242192ce3ed8bdb439ba40c0fe @@ -3449,6 +5634,29 @@ packages: - pkg:pypi/rich?source=hash-mapping size: 200323 timestamp: 1743371105291 +- conda: https://conda.anaconda.org/conda-forge/noarch/rich-14.1.0-pyhe01879c_0.conda + sha256: 3bda3cd6aa2ca8f266aeb8db1ec63683b4a7252d7832e8ec95788fb176d0e434 + md5: c41e49bd1f1479bed6c6300038c5466e + depends: + - markdown-it-py >=2.2.0 + - pygments >=2.13.0,<3.0.0 + - python >=3.9 + - typing_extensions >=4.0.0,<5.0.0 + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/rich?source=hash-mapping + size: 201098 + timestamp: 1753436991345 +- pypi: https://files.pythonhosted.org/packages/6d/4f/d073e09df851cfa251ef7840007d04db3293a0482ce607d2b993926089be/s3transfer-0.13.1-py3-none-any.whl + name: s3transfer + version: 0.13.1 + sha256: a981aa7429be23fe6dfc13e80e4020057cbab622b08c0315288758d67cabc724 + requires_dist: + - botocore>=1.37.4,<2.0a0 + - botocore[crt]>=1.37.4,<2.0a0 ; extra == 'crt' + requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/a6/f8/dae3421624fcc87a89d42e1898a798bc7ff72c61f38973a65d60df8f124c/safetensors-0.5.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl name: safetensors version: 0.5.3 @@ -3488,6 +5696,48 @@ packages: - safetensors[testing] ; extra == 'all' - safetensors[all] ; extra == 'dev' requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/8c/c9/bb114c158540ee17907ec470d01980957fdaf87b4aa07914c24eba87b9c6/safetensors-0.6.2-cp38-abi3-macosx_11_0_arm64.whl + name: safetensors + version: 0.6.2 + sha256: d6675cf4b39c98dbd7d940598028f3742e0375a6b4d4277e76beb0c35f4b843b + requires_dist: + - numpy>=1.21.6 ; extra == 'numpy' + - safetensors[numpy] ; extra == 'torch' + - torch>=1.10 ; extra == 'torch' + - safetensors[numpy] ; extra == 'tensorflow' + - tensorflow>=2.11.0 ; extra == 'tensorflow' + - safetensors[numpy] ; extra == 'pinned-tf' + - tensorflow==2.18.0 ; extra == 'pinned-tf' + - safetensors[numpy] ; extra == 'jax' + - flax>=0.6.3 ; extra == 'jax' + - jax>=0.3.25 ; extra == 'jax' + - jaxlib>=0.3.25 ; extra == 'jax' + - mlx>=0.0.9 ; extra == 'mlx' + - safetensors[numpy] ; extra == 'paddlepaddle' + - paddlepaddle>=2.4.1 ; extra == 'paddlepaddle' + - ruff ; extra == 'quality' + - safetensors[numpy] ; extra == 'testing' + - h5py>=3.7.0 ; extra == 'testing' + - huggingface-hub>=0.12.1 ; extra == 'testing' + - setuptools-rust>=1.5.2 ; extra == 'testing' + - pytest>=7.2.0 ; extra == 'testing' + - pytest-benchmark>=4.0.0 ; extra == 'testing' + - hypothesis>=6.70.2 ; extra == 'testing' + - safetensors[numpy] ; extra == 'testingfree' + - huggingface-hub>=0.12.1 ; extra == 'testingfree' + - setuptools-rust>=1.5.2 ; extra == 'testingfree' + - pytest>=7.2.0 ; extra == 'testingfree' + - pytest-benchmark>=4.0.0 ; extra == 'testingfree' + - hypothesis>=6.70.2 ; extra == 'testingfree' + - safetensors[torch] ; extra == 'all' + - safetensors[numpy] ; extra == 'all' + - safetensors[pinned-tf] ; extra == 'all' + - safetensors[jax] ; extra == 'all' + - safetensors[paddlepaddle] ; extra == 'all' + - safetensors[quality] ; extra == 'all' + - safetensors[testing] ; extra == 'all' + - safetensors[all] ; extra == 'dev' + requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/29/7a/8bce8968883e9465de20be15542f4c7e221952441727c4dad24d534c6d99/scikit_learn-1.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl name: scikit-learn version: 1.6.1 @@ -3550,6 +5800,67 @@ packages: - pooch>=1.6.0 ; extra == 'tests' - conda-lock==2.5.6 ; extra == 'maintenance' requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/67/4e/899317092f5efcab0e9bc929e3391341cec8fb0e816c4789686770024580/scikit_learn-1.7.1-cp312-cp312-macosx_12_0_arm64.whl + name: scikit-learn + version: 1.7.1 + sha256: 2fd8b8d35817b0d9ebf0b576f7d5ffbbabdb55536b0655a8aaae629d7ffd2e1f + requires_dist: + - numpy>=1.22.0 + - scipy>=1.8.0 + - joblib>=1.2.0 + - threadpoolctl>=3.1.0 + - numpy>=1.22.0 ; extra == 'build' + - scipy>=1.8.0 ; extra == 'build' + - cython>=3.0.10 ; extra == 'build' + - meson-python>=0.17.1 ; extra == 'build' + - numpy>=1.22.0 ; extra == 'install' + - scipy>=1.8.0 ; extra == 'install' + - joblib>=1.2.0 ; extra == 'install' + - threadpoolctl>=3.1.0 ; extra == 'install' + - matplotlib>=3.5.0 ; extra == 'benchmark' + - pandas>=1.4.0 ; extra == 'benchmark' + - memory-profiler>=0.57.0 ; extra == 'benchmark' + - matplotlib>=3.5.0 ; extra == 'docs' + - scikit-image>=0.19.0 ; extra == 'docs' + - pandas>=1.4.0 ; extra == 'docs' + - seaborn>=0.9.0 ; extra == 'docs' + - memory-profiler>=0.57.0 ; extra == 'docs' + - sphinx>=7.3.7 ; extra == 'docs' + - sphinx-copybutton>=0.5.2 ; extra == 'docs' + - sphinx-gallery>=0.17.1 ; extra == 'docs' + - numpydoc>=1.2.0 ; extra == 'docs' + - pillow>=8.4.0 ; extra == 'docs' + - pooch>=1.6.0 ; extra == 'docs' + - sphinx-prompt>=1.4.0 ; extra == 'docs' + - sphinxext-opengraph>=0.9.1 ; extra == 'docs' + - plotly>=5.14.0 ; extra == 'docs' + - polars>=0.20.30 ; extra == 'docs' + - sphinx-design>=0.5.0 ; extra == 'docs' + - sphinx-design>=0.6.0 ; extra == 'docs' + - sphinxcontrib-sass>=0.3.4 ; extra == 'docs' + - pydata-sphinx-theme>=0.15.3 ; extra == 'docs' + - sphinx-remove-toctrees>=1.0.0.post1 ; extra == 'docs' + - towncrier>=24.8.0 ; extra == 'docs' + - matplotlib>=3.5.0 ; extra == 'examples' + - scikit-image>=0.19.0 ; extra == 'examples' + - pandas>=1.4.0 ; extra == 'examples' + - seaborn>=0.9.0 ; extra == 'examples' + - pooch>=1.6.0 ; extra == 'examples' + - plotly>=5.14.0 ; extra == 'examples' + - matplotlib>=3.5.0 ; extra == 'tests' + - scikit-image>=0.19.0 ; extra == 'tests' + - pandas>=1.4.0 ; extra == 'tests' + - pytest>=7.1.2 ; extra == 'tests' + - pytest-cov>=2.9.0 ; extra == 'tests' + - ruff>=0.11.7 ; extra == 'tests' + - mypy>=1.15 ; extra == 'tests' + - pyamg>=4.2.1 ; extra == 'tests' + - polars>=0.20.30 ; extra == 'tests' + - pyarrow>=12.0.0 ; extra == 'tests' + - numpydoc>=1.2.0 ; extra == 'tests' + - pooch>=1.6.0 ; extra == 'tests' + - conda-lock==3.0.1 ; extra == 'maintenance' + requires_python: '>=3.10' - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.16.0-py312hf734454_0.conda sha256: 8406e26bf853e699b1ea97792f63987808783ff4ab6ddeff9cf1ec0b9d1aa342 md5: 7513ac56209d27a85ffa1582033f10a8 @@ -3573,6 +5884,30 @@ packages: - pkg:pypi/scipy?source=hash-mapping size: 16847456 timestamp: 1751148548291 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.16.1-py312h286a95b_0.conda + sha256: 2d9d0173b58010c2ee09280b7e4fa185d191380a4f042698263b4ffa2671818b + md5: 9841d229c34dbca6fd039e76cfca307b + depends: + - __osx >=11.0 + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - libcxx >=19 + - libgfortran + - libgfortran5 >=14.3.0 + - libgfortran5 >=15.1.0 + - liblapack >=3.9.0,<4.0a0 + - numpy <2.6 + - numpy >=1.23,<3 + - numpy >=1.25.2 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/scipy?source=hash-mapping + size: 13840981 + timestamp: 1754970654942 - conda: https://conda.anaconda.org/conda-forge/noarch/seaborn-0.13.2-hd8ed1ab_3.conda noarch: python sha256: ea29a69b14dd6be5cdeeaa551bf50d78cafeaf0351e271e358f9b820fcab4cb0 @@ -3628,6 +5963,17 @@ packages: - pkg:pypi/setuptools?source=compressed-mapping size: 777736 timestamp: 1740654030775 +- conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda + sha256: 972560fcf9657058e3e1f97186cc94389144b46dbdf58c807ce62e83f977e863 + md5: 4de79c071274a53dcaf2a8c749d1499e + depends: + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/setuptools?source=hash-mapping + size: 748788 + timestamp: 1748804951958 - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda sha256: 458227f759d5e3fcec5d9b7acce54e10c9e1f4f4b7ec978f3bfd54ce4ee9853d md5: 3339e3b65d58accf4ca4fb8748ab16b3 @@ -3637,7 +5983,7 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/six?source=compressed-mapping + - pkg:pypi/six?source=hash-mapping size: 18455 timestamp: 1753199211006 - pypi: https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl @@ -3678,6 +6024,26 @@ packages: - pkg:pypi/statsmodels?source=hash-mapping size: 12062670 timestamp: 1751917720541 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/statsmodels-0.14.5-py312hcde60ef_0.conda + sha256: 911a6fcfa2c04de64d03378e705a0678bf511f25aa0f5f9c8e4570ccb071b241 + md5: 79208bf3a11cedbe7dd53a6798cb88d2 + depends: + - __osx >=11.0 + - numpy <3,>=1.22.3 + - numpy >=1.23,<3 + - packaging >=21.3 + - pandas !=2.1.0,>=1.4 + - patsy >=0.5.6 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + - scipy !=1.9.2,>=1.8 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/statsmodels?source=hash-mapping + size: 11703160 + timestamp: 1751918258652 - pypi: https://files.pythonhosted.org/packages/b2/fe/81695a1aa331a842b582453b605175f419fe8540355886031328089d840a/sympy-1.13.1-py3-none-any.whl name: sympy version: 1.13.1 @@ -3687,6 +6053,15 @@ packages: - pytest>=7.1.0 ; extra == 'dev' - hypothesis>=6.70.0 ; extra == 'dev' requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl + name: sympy + version: 1.14.0 + sha256: e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5 + requires_dist: + - mpmath>=1.1.0,<1.4 + - pytest>=7.1.0 ; extra == 'dev' + - hypothesis>=6.70.0 ; extra == 'dev' + requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl name: tenacity version: 9.1.2 @@ -3714,6 +6089,17 @@ packages: purls: [] size: 3318875 timestamp: 1699202167581 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h892fb3f_2.conda + sha256: cb86c522576fa95c6db4c878849af0bccfd3264daf0cc40dd18e7f4a7bfced0e + md5: 7362396c170252e7b7b0c8fb37fe9c78 + depends: + - __osx >=11.0 + - libzlib >=1.3.1,<2.0a0 + license: TCL + license_family: BSD + purls: [] + size: 3125538 + timestamp: 1748388189063 - pypi: https://files.pythonhosted.org/packages/8a/63/38be071b0c8e06840bc6046991636bcb30c27f6bb1e670f4f4bc87cf49cc/tokenizers-0.21.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl name: tokenizers version: 0.21.1 @@ -3731,6 +6117,23 @@ packages: - setuptools-rust ; extra == 'docs' - tokenizers[testing] ; extra == 'dev' requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/8d/a6/28975479e35ddc751dc1ddc97b9b69bf7fcf074db31548aab37f8116674c/tokenizers-0.21.4-cp39-abi3-macosx_11_0_arm64.whl + name: tokenizers + version: 0.21.4 + sha256: 5e2f601a8e0cd5be5cc7506b20a79112370b9b3e9cb5f13f68ab11acd6ca7d60 + requires_dist: + - huggingface-hub>=0.16.4,<1.0 + - pytest ; extra == 'testing' + - requests ; extra == 'testing' + - numpy ; extra == 'testing' + - datasets ; extra == 'testing' + - black==22.3 ; extra == 'testing' + - ruff ; extra == 'testing' + - sphinx ; extra == 'docs' + - sphinx-rtd-theme ; extra == 'docs' + - setuptools-rust ; extra == 'docs' + - tokenizers[testing] ; extra == 'dev' + requires_python: '>=3.9' - conda: https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_1.conda sha256: 34f3a83384ac3ac30aefd1309e69498d8a4aa0bf2d1f21c645f79b180e378938 md5: b0dd904de08b7db706167240bf37b164 @@ -3783,6 +6186,37 @@ packages: - opt-einsum>=3.3 ; extra == 'opt-einsum' - optree>=0.13.0 ; extra == 'optree' requires_python: '>=3.9.0' +- pypi: https://files.pythonhosted.org/packages/be/66/5c9a321b325aaecb92d4d1855421e3a055abd77903b7dab6575ca07796db/torch-2.8.0-cp312-none-macosx_11_0_arm64.whl + name: torch + version: 2.8.0 + sha256: 619c2869db3ada2c0105487ba21b5008defcc472d23f8b80ed91ac4a380283b0 + requires_dist: + - filelock + - typing-extensions>=4.10.0 + - setuptools ; python_full_version >= '3.12' + - sympy>=1.13.3 + - networkx + - jinja2 + - fsspec + - nvidia-cuda-nvrtc-cu12==12.8.93 ; platform_machine == 'x86_64' and sys_platform == 'linux' + - nvidia-cuda-runtime-cu12==12.8.90 ; platform_machine == 'x86_64' and sys_platform == 'linux' + - nvidia-cuda-cupti-cu12==12.8.90 ; platform_machine == 'x86_64' and sys_platform == 'linux' + - nvidia-cudnn-cu12==9.10.2.21 ; platform_machine == 'x86_64' and sys_platform == 'linux' + - nvidia-cublas-cu12==12.8.4.1 ; platform_machine == 'x86_64' and sys_platform == 'linux' + - nvidia-cufft-cu12==11.3.3.83 ; platform_machine == 'x86_64' and sys_platform == 'linux' + - nvidia-curand-cu12==10.3.9.90 ; platform_machine == 'x86_64' and sys_platform == 'linux' + - nvidia-cusolver-cu12==11.7.3.90 ; platform_machine == 'x86_64' and sys_platform == 'linux' + - nvidia-cusparse-cu12==12.5.8.93 ; platform_machine == 'x86_64' and sys_platform == 'linux' + - nvidia-cusparselt-cu12==0.7.1 ; platform_machine == 'x86_64' and sys_platform == 'linux' + - nvidia-nccl-cu12==2.27.3 ; platform_machine == 'x86_64' and sys_platform == 'linux' + - nvidia-nvtx-cu12==12.8.90 ; platform_machine == 'x86_64' and sys_platform == 'linux' + - nvidia-nvjitlink-cu12==12.8.93 ; platform_machine == 'x86_64' and sys_platform == 'linux' + - nvidia-cufile-cu12==1.13.1.3 ; platform_machine == 'x86_64' and sys_platform == 'linux' + - triton==3.4.0 ; platform_machine == 'x86_64' and sys_platform == 'linux' + - optree>=0.13.0 ; extra == 'optree' + - opt-einsum>=3.3 ; extra == 'opt-einsum' + - pyyaml ; extra == 'pyyaml' + requires_python: '>=3.9.0' - pypi: https://files.pythonhosted.org/packages/65/13/26c37c5433658d3f1eb30be07a4b42b29893bc42ff7cb7261ef6e474fc3c/torchtext-0.18.0-cp312-cp312-manylinux1_x86_64.whl name: torchtext version: 0.18.0 @@ -3793,6 +6227,16 @@ packages: - torch>=2.3.0 - numpy requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/8b/80/c78f88844e576c21580e64bd93de9df9bca223fef3e8195345680eb6f87f/torchtext-0.18.0-cp312-cp312-macosx_11_0_arm64.whl + name: torchtext + version: 0.18.0 + sha256: fec43696fb6fa7573e740a8175fd69681106574fd1fc840211182d941b88a2ba + requires_dist: + - tqdm + - requests + - torch>=2.3.0 + - numpy + requires_python: '>=3.8' - pypi: https://files.pythonhosted.org/packages/36/63/0722e153fd27d64d5b0af45b5c8cb0e80b35a68cf0130303bc9a8bb095c7/torchvision-0.21.0-cp312-cp312-manylinux1_x86_64.whl name: torchvision version: 0.21.0 @@ -3804,6 +6248,17 @@ packages: - gdown>=4.7.3 ; extra == 'gdown' - scipy ; extra == 'scipy' requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/df/1d/0ea0b34bde92a86d42620f29baa6dcbb5c2fc85990316df5cb8f7abb8ea2/torchvision-0.23.0-cp312-cp312-macosx_11_0_arm64.whl + name: torchvision + version: 0.23.0 + sha256: e0e2c04a91403e8dd3af9756c6a024a1d9c0ed9c0d592a8314ded8f4fe30d440 + requires_dist: + - numpy + - torch==2.8.0 + - pillow>=5.3.0,!=8.3.* + - gdown>=4.7.3 ; extra == 'gdown' + - scipy ; extra == 'scipy' + requires_python: '>=3.9' - conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.1-py312h66e93f0_0.conda sha256: c96be4c8bca2431d7ad7379bad94ed6d4d25cd725ae345540a531d9e26e148c9 md5: c532a6ee766bed75c4fa0c39e959d132 @@ -3818,6 +6273,20 @@ packages: - pkg:pypi/tornado?source=hash-mapping size: 850902 timestamp: 1748003427956 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/tornado-6.5.2-py312h163523d_0.conda + sha256: 82ceea2527ac484f5c8d7dee95033935b7fecb0b42afb2d9538f7397404aa6d8 + md5: 181a5ca410bad66be792da0e11038016 + depends: + - __osx >=11.0 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/tornado?source=hash-mapping + size: 853490 + timestamp: 1754732280524 - pypi: https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl name: tqdm version: 4.67.1 @@ -4269,6 +6738,18 @@ packages: - pkg:pypi/typing-extensions?source=hash-mapping size: 52077 timestamp: 1743201626659 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.14.1-pyhe01879c_0.conda + sha256: 4f52390e331ea8b9019b87effaebc4f80c6466d09f68453f52d5cdc2a3e1194f + md5: e523f4f1e980ed7a4240d7e27e9ec81f + depends: + - python >=3.9 + - python + license: PSF-2.0 + license_family: PSF + purls: + - pkg:pypi/typing-extensions?source=hash-mapping + size: 51065 + timestamp: 1751643513473 - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda sha256: 5aaa366385d716557e365f0a4e9c3fca43ba196872abbbe3d56bb610d131e192 md5: 4222072737ccff51314b5ece9c7d6f5a @@ -4292,6 +6773,22 @@ packages: - pkg:pypi/ukkonen?source=hash-mapping size: 13904 timestamp: 1725784191021 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ukkonen-1.0.1-py312h6142ec9_5.conda + sha256: 1e4452b4a12d8a69c237f14b876fbf0cdc456914170b49ba805779c749c31eca + md5: 2b485a809d1572cbe7f0ad9ee107e4b0 + depends: + - __osx >=11.0 + - cffi + - libcxx >=17 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ukkonen?source=hash-mapping + size: 13605 + timestamp: 1725784243533 - conda: https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-16.0.0-py312h66e93f0_0.conda sha256: 638916105a836973593547ba5cf4891d1f2cb82d1cf14354fcef93fd5b941cdc md5: 617f5d608ff8c28ad546e5d9671cbb95 @@ -4306,6 +6803,20 @@ packages: - pkg:pypi/unicodedata2?source=hash-mapping size: 404401 timestamp: 1736692621599 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/unicodedata2-16.0.0-py312hea69d52_0.conda + sha256: c6ca9ea11eecc650df4bce4b3daa843821def6d753eeab6d81de35bb43f9d984 + md5: 9a835052506b91ea8f0d8e352cd12246 + depends: + - __osx >=11.0 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/unicodedata2?source=hash-mapping + size: 409745 + timestamp: 1736692768349 - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.3.0-pyhd8ed1ab_0.conda sha256: 114919ffa80c328127dab9c8e7a38f9d563c617691fb81fccb11c1e86763727e md5: 32674f8dbfb7b26410ed580dd3c10a29 @@ -4321,6 +6832,21 @@ packages: - pkg:pypi/urllib3?source=hash-mapping size: 100102 timestamp: 1734859520452 +- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.5.0-pyhd8ed1ab_0.conda + sha256: 4fb9789154bd666ca74e428d973df81087a697dbb987775bc3198d2215f240f8 + md5: 436c165519e140cb08d246a4472a9d6a + depends: + - brotli-python >=1.0.9 + - h2 >=4,<5 + - pysocks >=1.5.6,<2.0,!=1.5.7 + - python >=3.9 + - zstandard >=0.18.0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/urllib3?source=hash-mapping + size: 101735 + timestamp: 1750271478254 - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.33.1-pyhd8ed1ab_0.conda sha256: 7b8328d79cb7ec19929ec955fe4dbb938d35da391a74a3974c47ca2622c64b04 md5: 3f6ee060b1462c29b3442df71939a358 @@ -4335,6 +6861,21 @@ packages: - pkg:pypi/virtualenv?source=compressed-mapping size: 4138678 timestamp: 1754419391413 +- conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.34.0-pyhd8ed1ab_0.conda + sha256: 398f40090e80ec5084483bb798555d0c5be3d1bb30f8bb5e4702cd67cdb595ee + md5: 2bd6c0c96cfc4dbe9bde604a122e3e55 + depends: + - distlib >=0.3.7,<1 + - filelock >=3.12.2,<4 + - platformdirs >=3.9.1,<5 + - python >=3.9 + - typing_extensions >=4.13.2 + license: MIT + license_family: MIT + purls: + - pkg:pypi/virtualenv?source=compressed-mapping + size: 4381624 + timestamp: 1755111905876 - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.24.0-h3e06ad9_0.conda sha256: ba673427dcd480cfa9bbc262fd04a9b1ad2ed59a159bd8f7e750d4c52282f34c md5: 0f2ca7906bf166247d1d760c3422cb8a @@ -4366,6 +6907,11 @@ packages: - pkg:pypi/wheel?source=hash-mapping size: 62931 timestamp: 1733130309598 +- pypi: https://files.pythonhosted.org/packages/ca/51/5447876806d1088a0f8f71e16542bf350918128d0a69437df26047c8e46f/widgetsnbextension-4.0.14-py3-none-any.whl + name: widgetsnbextension + version: 4.0.14 + sha256: 4875a9eaf72fbf5079dc372a51a9f268fc38d46f767cbf85c43a36da5cb9b575 + requires_python: '>=3.7' - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-h4f16b4b_2.conda sha256: ad8cab7e07e2af268449c2ce855cbb51f43f4664936eff679b1f3862e6e4b01d md5: fdc27cb255a7a2cc73b7919a968b48f0 @@ -4497,6 +7043,16 @@ packages: purls: [] size: 14780 timestamp: 1734229004433 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/xorg-libxau-1.0.12-h5505292_0.conda + sha256: f33e6f013fc36ebc200f09ddead83468544cb5c353a3b50499b07b8c34e28a8d + md5: 50901e0764b7701d8ed7343496f4f301 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 13593 + timestamp: 1734229104321 - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcomposite-0.4.6-hb9d3cd8_2.conda sha256: 753f73e990c33366a91fd42cc17a3d19bb9444b9ca5ff983605fa9e953baf57f md5: d3c295b50f092ab525ffe3c2aa4b7413 @@ -4549,6 +7105,16 @@ packages: purls: [] size: 19901 timestamp: 1727794976192 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/xorg-libxdmcp-1.1.5-hd74edd7_0.conda + sha256: 9939a166d780700d81023546759102b33fdc2c5f11ef09f5f66c77210fd334c8 + md5: 77c447f48cab5d3a15ac224edb86a968 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 18487 + timestamp: 1727795205022 - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.6-hb9d3cd8_0.conda sha256: da5dc921c017c05f38a38bd75245017463104457b63a1ce633ed41f214159c14 md5: febbab7d15033c913d53c7a2c102309d @@ -4651,6 +7217,16 @@ packages: purls: [] size: 85189 timestamp: 1753484064210 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h925e9cb_3.conda + sha256: b03433b13d89f5567e828ea9f1a7d5c5d697bf374c28a4168d71e9464f5dafac + md5: 78a0fe9e9c50d2c381e8ee47e3ea437d + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 83386 + timestamp: 1753484079473 - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.21.0-pyhd8ed1ab_1.conda sha256: 567c04f124525c97a096b65769834b7acb047db24b15a56888a322bf3966c3e1 md5: 0c3cc595284c5e8f0f9900a9b228a332 @@ -4662,6 +7238,29 @@ packages: - pkg:pypi/zipp?source=hash-mapping size: 21809 timestamp: 1732827613585 +- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhd8ed1ab_0.conda + sha256: 7560d21e1b021fd40b65bfb72f67945a3fcb83d78ad7ccf37b8b3165ec3b68ad + md5: df5e78d904988eb55042c0c97446079f + depends: + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/zipp?source=hash-mapping + size: 22963 + timestamp: 1749421737203 +- conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda + sha256: 5d7c0e5f0005f74112a34a7425179f4eb6e73c92f5d109e6af4ddeca407c92ab + md5: c9f075ab2f33b3bbee9e62d4ad0a6cd8 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libzlib 1.3.1 hb9d3cd8_2 + license: Zlib + license_family: Other + purls: [] + size: 92286 + timestamp: 1727963153079 - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.23.0-py312h66e93f0_1.conda sha256: b4fd6bd1cb87a183a8bbe85b4e87a1e7c51473309d0d82cd88d38fb021bcf41e md5: d28b82fcc8d1b462b595af4b15a6cdcf @@ -4677,10 +7276,29 @@ packages: - pkg:pypi/zstandard?source=hash-mapping size: 731658 timestamp: 1741853415477 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.23.0-py312hea69d52_2.conda + sha256: c499a2639c2981ac2fd33bae2d86c15d896bc7524f1c5651a7d3b088263f7810 + md5: ba0eb639914e4033e090b46f53bec31c + depends: + - __osx >=11.0 + - cffi >=1.11 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/zstandard?source=hash-mapping + size: 532173 + timestamp: 1745870087418 - pypi: https://files.pythonhosted.org/packages/92/a7/5f4c6c2a62dd88f58133e333af1c251dd08f98d48445f650889d85e43b7b/zstd-1.5.6.7.tar.gz name: zstd version: 1.5.6.7 sha256: b3fa8f6bfb5e116b950ad633edccae4f65055a213ab4c00c1d4397f4b257b697 +- pypi: https://files.pythonhosted.org/packages/08/b8/2bc2590a34c733ea0570f366e6ad7d889d05c7825bd3ccab01f36ece71c6/zstd-1.5.7.2-cp312-cp312-macosx_11_0_arm64.whl + name: zstd + version: 1.5.7.2 + sha256: ef201b6f7d3a6751d85cc52f9e6198d4d870e83d490172016b64a6dd654a9583 - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda sha256: a4166e3d8ff4e35932510aaff7aa90772f84b4d07e9f6f83c614cba7ceefe0eb md5: 6432cb5d4ac0046c3ac0a8a0f95842f9 @@ -4694,3 +7312,14 @@ packages: purls: [] size: 567578 timestamp: 1742433379869 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-h6491c7d_2.conda + sha256: 0d02046f57f7a1a3feae3e9d1aa2113788311f3cf37a3244c71e61a93177ba67 + md5: e6f69c7bcccdefa417f056fa593b40f0 + depends: + - __osx >=11.0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 399979 + timestamp: 1742433432699 diff --git a/pyproject.toml b/pyproject.toml index 0effea71..45961807 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ name = "esm" version = "3.2.1" description = "EvolutionaryScale open model repository" readme = "README.md" -requires-python = ">=3.10" +requires-python = ">=3.10,<3.13" license = {file = "LICENSE.txt"} authors = [ @@ -18,6 +18,8 @@ classifiers = [ "Development Status :: 3 - Alpha", "Topic :: Scientific/Engineering :: Bio-Informatics", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ] dependencies = [ @@ -37,8 +39,23 @@ dependencies = [ "cloudpathlib", "httpx", "tenacity", - "zstd" + "zstd", + "ipywidgets", + "py3dmol", + "pydssp", + "boto3", + "pygtrie", + "dna_features_viewer", + "flash-attn @ https://github.com/Dao-AILab/flash-attention/releases/download/v2.8.1/flash_attn-2.8.1+cu12torch2.7cxx11abiFALSE-cp312-cp312-linux_x86_64.whl" ] +# Pytest +[tool.pytest.ini_options] +addopts = """ + --cov=esm + --cov-report term-missing:skip-covered + -n auto + --ignore=tests/oss_pytests/test_oss_client.py +""" [tool.setuptools] package-dir = {"" = "."} @@ -53,7 +70,7 @@ esm = ["data/*"] [tool.pixi.project] channels = ["conda-forge"] -platforms = ["linux-64"] +platforms = ["linux-64", "osx-arm64"] # These are build dependencies, to ensure pip support, keep run-time deps above in `dependencies` [tool.pixi.dependencies] @@ -61,6 +78,7 @@ pkg-config = "*" cmake = "*" pip = "*" twine = "*" +python = "3.12.*" [tool.pixi.pypi-dependencies] esm = { path = ".", editable = true } @@ -74,7 +92,9 @@ matplotlib = "*" pre-commit = "*" pytest = "*" pytest-cov = "*" +pytest-xdist = "*" seaborn = "*" +pyright = "==1.1.399" [tool.pixi.feature.dev.tasks] lint-all = "pre-commit run --all-files --show-diff-on-failure" @@ -83,3 +103,44 @@ cov-test = "pytest -v --junitxml=pytest.xml --cov=esm" [tool.pixi.environments] default = {features = [], solve-group = "default"} dev = {features = ["dev"], solve-group = "default"} + +[tool.ruff] +extend-include = ["*.ipynb"] + +[tool.ruff.lint] +# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`), sort imports ('I') +select = ["E4", "E7", "E9", "F", "I"] +ignore = [ + # allow variable == False (tensors should do this) + "E712", + # allow assigning of lambdas + "E731", + # Allow ambiguous variables, e.g. we use O for oxygen + "E741", + # Ignore errors from jaxtyping hints + # https://docs.kidger.site/jaxtyping/faq/#flake8-or-ruff-are-throwing-an-error + "F722", + # TODO: Fix the few offenders in a follow up PR + "E721", +] + +[tool.ruff.lint.isort] +split-on-trailing-comma = false +known-third-party = ["wandb"] + +[tool.ruff.format] +skip-magic-trailing-comma = true +docstring-code-format = true +docstring-code-line-length = "dynamic" + +[tool.isort] +known_third_party = ["wandb"] + +[tool.pyright] +root = ['.'] +useLibraryCodeForTypes = true +reportPrivateImportUsage = false +typeCheckingMode = "basic" + +[tool.importlinter] +root_package = "esm" diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 00000000..5af442ea --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,15 @@ +# OSS-specific variables and commands +DOCKER_TAG ?= dev +DOCKER_IMAGE_OSS=oss_pytests:${DOCKER_TAG} + +build-oss-ci: + docker build -f oss_pytests/Dockerfile oss_pytests -t $(DOCKER_IMAGE_OSS) + +start-docker-oss: + docker run \ + --rm \ + -e URL=${URL} \ + -e ESM3_FORGE_TOKEN=${ESM3_FORGE_TOKEN} \ + --name=$(USER)-oss_pytests \ + --network=host \ + ${DOCKER_IMAGE_OSS} diff --git a/tests/oss_pytests/Dockerfile b/tests/oss_pytests/Dockerfile new file mode 100644 index 00000000..f10b2023 --- /dev/null +++ b/tests/oss_pytests/Dockerfile @@ -0,0 +1,19 @@ +# Dockerfile.sdktest +FROM python:3.12-slim + +# Install pip and basic dependencies +RUN apt-get update && apt-get install -y curl build-essential && rm -rf /var/lib/apt/lists/* + +# Set working directory +WORKDIR /tests + +# Copy requirements and install them (assumes esm-oss is one of them) +COPY requirements.txt . + +RUN pip install --no-cache-dir -r requirements.txt + +# Copy in the tests +COPY . . + +# Default command (can be overridden in docker run) +CMD ["pytest", "-v", "test_oss_client.py"] diff --git a/tests/oss_pytests/requirements.txt b/tests/oss_pytests/requirements.txt new file mode 100644 index 00000000..d120ce35 --- /dev/null +++ b/tests/oss_pytests/requirements.txt @@ -0,0 +1,3 @@ +esm +pytest +httpx # TODO(williamxi): Remove this after the esm repo is fixed diff --git a/tests/oss_pytests/test_oss_client.py b/tests/oss_pytests/test_oss_client.py new file mode 100644 index 00000000..6fa4a30d --- /dev/null +++ b/tests/oss_pytests/test_oss_client.py @@ -0,0 +1,85 @@ +import os + +import pytest + +from esm.sdk import client # pyright: ignore +from esm.sdk.api import ( # pyright: ignore + ESMProtein, + ESMProteinTensor, + ForwardAndSampleOutput, + GenerationConfig, + LogitsConfig, + LogitsOutput, + SamplingConfig, + SamplingTrackConfig, +) +from esm.sdk.forge import SequenceStructureForgeInferenceClient # pyright: ignore + +API_TOKEN = os.environ.get("ESM3_FORGE_TOKEN", "") +URL = os.environ.get("URL") + + +@pytest.mark.sdk +def test_oss_esm3_client(): + assert URL is not None + + sequence = "MALWMRLLPLLALLAL___PDPAAA" + model = "esm3-small-2024-03" + esm3_client = client(model=model, url=URL, token=API_TOKEN) + protein = ESMProtein(sequence) + + encoded_protein = esm3_client.encode(input=protein) + assert isinstance(encoded_protein, ESMProteinTensor) + + decoded_protein = esm3_client.decode(input=encoded_protein) + assert isinstance(decoded_protein, ESMProtein) + + logits_config = LogitsConfig(sequence=True, return_embeddings=True) + result = esm3_client.logits(input=encoded_protein, config=logits_config) + assert isinstance(result, LogitsOutput) + + sampling_config = SamplingConfig(sequence=SamplingTrackConfig(temperature=0.1)) + result = esm3_client.forward_and_sample( + input=encoded_protein, sampling_configuration=sampling_config + ) + assert isinstance(result, ForwardAndSampleOutput) + + generation_config = GenerationConfig(track="sequence", num_steps=4) + result = esm3_client.generate(input=protein, config=generation_config) + assert isinstance(result, ESMProtein) + + +@pytest.mark.sdk +def test_oss_esmc_client(): + assert URL is not None + + sequence = "MALWMRLLPLLALLALAVUUPDPAAA" + model = "esmc-300m-2024-12" + esmc_client = client(model=model, url=URL, token=API_TOKEN) + + protein = ESMProtein(sequence) + encoded_protein = esmc_client.encode(input=protein) + assert isinstance(encoded_protein, ESMProteinTensor) + + decoded_protein = esmc_client.decode(input=encoded_protein) + assert isinstance(decoded_protein, ESMProtein) + + logits_config = LogitsConfig( + sequence=True, return_embeddings=True, return_hidden_states=True + ) + result = esmc_client.logits(input=encoded_protein, config=logits_config) + assert isinstance(result, LogitsOutput) + + +@pytest.mark.sdk +def test_oss_sequence_structure_forge_inference_client(): + assert URL is not None + + sequence = "MALWMRLLPLLALLALAVUUPDPAAA" + model = "esm3-small-2024-03" + client = SequenceStructureForgeInferenceClient( + model=model, url=URL, token=API_TOKEN + ) + + encoded_protein = client.fold(sequence=sequence) + assert isinstance(encoded_protein, ESMProtein) diff --git a/tests/oss_pytests/test_placeholder.py b/tests/oss_pytests/test_placeholder.py new file mode 100644 index 00000000..a3b975ad --- /dev/null +++ b/tests/oss_pytests/test_placeholder.py @@ -0,0 +1,6 @@ +import pytest + + +@pytest.mark.skip(reason="no other tests in this suite") +def test_placeholder(): + pass From fe8aa273c235f89a5df2a34f9d33ed8c7e2ceadc Mon Sep 17 00:00:00 2001 From: Ishaan Mathur Date: Mon, 18 Aug 2025 19:36:36 +0000 Subject: [PATCH 09/11] updating token --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9482116d..53e317ec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,11 +56,12 @@ jobs: env: DOCKER_TAG: ${{ github.sha }} FORGE_URL: https://forge.evolutionaryscale.ai/ + ESM3_FORGE_TOKEN: ${{ secrets.ESM3_FORGE_TOKEN }} run: | set -e cd tests make build-oss-ci - make start-docker-oss URL=${{ env.FORGE_URL }} DOCKER_TAG=${{ env.DOCKER_TAG }} ESM3_FORGE_TOKEN=${{ secrets.ESM3_FORGE_TOKEN }} + make start-docker-oss URL=${{ env.FORGE_URL }} DOCKER_TAG=${{ env.DOCKER_TAG }} ESM3_FORGE_TOKEN=${{ env.ESM3_FORGE_TOKEN }} shell: pixi run bash -e {0} - name: cleanup docker containers if they're hanging From 4624158ebc7d67864f330168085830ed8fd096eb Mon Sep 17 00:00:00 2001 From: Ishaan Mathur Date: Mon, 18 Aug 2025 21:16:27 +0000 Subject: [PATCH 10/11] removing python 3.10 and 3.11 as supported versions --- pixi.lock | 2 +- pyproject.toml | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/pixi.lock b/pixi.lock index c392edf5..0ab625bf 100644 --- a/pixi.lock +++ b/pixi.lock @@ -1731,7 +1731,7 @@ packages: - pypi: ./ name: esm version: 3.2.1 - sha256: 5456e12b3d09b96bb576d68a9f74ea445e11a4936b72488d878d0149523b0870 + sha256: 0126874c673ed5fa21ae9d1a040b15845227a3faca844c18ed5f8f7644e66b7e requires_dist: - torch>=2.2.0 - torchvision diff --git a/pyproject.toml b/pyproject.toml index 45961807..1f7de6b1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,8 +17,6 @@ maintainers = [ classifiers = [ "Development Status :: 3 - Alpha", "Topic :: Scientific/Engineering :: Bio-Informatics", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", ] From 125166fe83b71d62810fdca5e96656b037ff080e Mon Sep 17 00:00:00 2001 From: Ishaan Mathur Date: Mon, 18 Aug 2025 21:28:13 +0000 Subject: [PATCH 11/11] updating version in one more spot --- pixi.lock | 4 ++-- pyproject.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pixi.lock b/pixi.lock index 0ab625bf..f5f12d46 100644 --- a/pixi.lock +++ b/pixi.lock @@ -1731,7 +1731,7 @@ packages: - pypi: ./ name: esm version: 3.2.1 - sha256: 0126874c673ed5fa21ae9d1a040b15845227a3faca844c18ed5f8f7644e66b7e + sha256: 114cd4b1eee83b5f746b9da2a2509c36faecefed37bace6de1a910c71a108f4b requires_dist: - torch>=2.2.0 - torchvision @@ -1757,7 +1757,7 @@ packages: - pygtrie - dna-features-viewer - flash-attn @ https://github.com/Dao-AILab/flash-attention/releases/download/v2.8.1/flash_attn-2.8.1+cu12torch2.7cxx11abiFALSE-cp312-cp312-linux_x86_64.whl - requires_python: '>=3.10,<3.13' + requires_python: '>=3.12,<3.13' editable: true - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda sha256: ce61f4f99401a4bd455b89909153b40b9c823276aefcbb06f2044618696009ca diff --git a/pyproject.toml b/pyproject.toml index 1f7de6b1..943a06c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ name = "esm" version = "3.2.1" description = "EvolutionaryScale open model repository" readme = "README.md" -requires-python = ">=3.10,<3.13" +requires-python = ">=3.12,<3.13" license = {file = "LICENSE.txt"} authors = [