diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..887a2c18 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# SCM syntax highlighting & preventing 3-way merges +pixi.lock merge=binary linguist-language=YAML linguist-generated=true diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..042fd93e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,37 @@ +--- +name: Bug report +about: Something is broken in the build or packaging pipeline +title: "fix: " +labels: bug +assignees: "" +--- + +## Environment + +- **OS / Platform**: +- **Python version**: +- **ITK version / branch**: +- **Script / entry point used**: + +## Steps to Reproduce + + +## Expected Behavior + + + +## Actual Behavior + + + +
+Log output + +``` +``` + +
+ +## Additional Context + + diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..07191d51 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: true +contact_links: + - name: ITK Discourse (questions & support) + url: https://discourse.itk.org + about: For build questions or general ITK support, please use the ITK Discourse forum. + - name: ITK Documentation + url: https://itkpythonpackage.readthedocs.io + about: Check the docs before filing an issue. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..f54cb07a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,23 @@ +--- +name: Feature request +about: Suggest a new capability or improvement to the build/packaging pipeline +title: "feat: " +labels: enhancement +assignees: "" +--- + +## Problem / Motivation + + + +## Proposed Solution + + + +## Alternatives Considered + + + +## Additional Context + + diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..fa1ada99 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,30 @@ +## Summary + + + +## Type of Change + +- [ ] Bug fix +- [ ] New feature / enhancement +- [ ] Refactor / cleanup +- [ ] Docs / CI only + +## Checklist + +- [ ] Pre-commit hooks pass locally (`pre-commit run --all-files`) +- [ ] Tested wheel build on affected platform(s) (Linux / macOS / Windows) +- [ ] Docs updated if behavior changed (`docs/`) +- [ ] Commit messages follow Conventional Commits (`feat:`, `fix:`, `chore:`, etc.) + +## Platform(s) Tested + + +- [ ] Linux x86_64 (manylinux) +- [ ] Linux aarch64 (manylinux) +- [ ] macOS x86_64 +- [ ] macOS arm64 +- [ ] Windows x86_64 + +## Related Issues + + diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml new file mode 100644 index 00000000..133a0df4 --- /dev/null +++ b/.github/workflows/docs.yaml @@ -0,0 +1,31 @@ +name: docs + +on: + pull_request: + paths: + - "docs/**" + - ".readthedocs.yml" + push: + branches: [main] + paths: + - "docs/**" + - ".readthedocs.yml" + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + - name: Install dependencies + run: pip install -r docs/requirements-docs.txt + - name: Build docs + run: sphinx-build -W --keep-going -b html docs docs/_build/html + - uses: actions/upload-artifact@v4 + if: always() + with: + name: docs-html + path: docs/_build/html + retention-days: 7 diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml new file mode 100644 index 00000000..f1356482 --- /dev/null +++ b/.github/workflows/pre-commit.yaml @@ -0,0 +1,16 @@ +name: pre-commit + +on: + pull_request: + push: + branches: [main] + +jobs: + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + - uses: pre-commit/action@v3.0.1 diff --git a/.gitignore b/.gitignore index cffba1ed..c49bb1de 100644 --- a/.gitignore +++ b/.gitignore @@ -43,7 +43,6 @@ lib lib64 MANIFEST oneTBB-prefix/ -pyproject.toml # Installer logs pip-log.txt @@ -73,3 +72,10 @@ docs/_build # IDE junk .idea/* *.swp +/itkVersion.py +# PyPI credentials +.pypirc + +# pixi environments +.pixi/* +!.pixi/config.toml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..8e3166d1 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,82 @@ +# Pre-commit configuration for ITKPythonPackage +# Run `pre-commit install` to install git hooks locally +# Run `pre-commit run --all-files` to check all files +# Run `pre-commit autoupdate` to update hook versions + +# Exclude generated/vendored directories from all hooks +exclude: ^(\.pixi|build|pixi.lock|docs)/ + +repos: + # General file hygiene + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + stages: [pre-commit] + - id: end-of-file-fixer + stages: [pre-commit] + - id: check-yaml + stages: [pre-commit] + - id: check-toml + stages: [pre-commit] + - id: check-merge-conflict + stages: [pre-commit] + - id: check-added-large-files + args: [--maxkb=500] + stages: [pre-commit] + # Enforce LF line endings everywhere except Windows PowerShell scripts + - id: mixed-line-ending + args: [--fix=lf] + exclude: \.ps1$ + stages: [pre-commit] + + # Python: formatting + - repo: https://github.com/psf/black + rev: 24.10.0 + hooks: + - id: black + stages: [pre-commit] + + # Python: linting + import sorting + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.8.6 + hooks: + - id: ruff + args: [--fix] + stages: [pre-commit] + + # Shell: linting + - repo: https://github.com/shellcheck-py/shellcheck-py + rev: v0.10.0.1 + hooks: + - id: shellcheck + stages: [pre-commit] + + # Shell: formatting + - repo: https://github.com/scop/pre-commit-shfmt + rev: v3.12.0-2 + hooks: + - id: shfmt + args: [-i, "2", -w] + stages: [pre-commit] + + # TOML: formatting + - repo: https://github.com/ComPWA/taplo-pre-commit + rev: v0.9.3 + hooks: + - id: taplo-format + stages: [pre-commit] + + # ITK commit message hooks (matching ITK/Utilities/Hooks/) + - repo: local + hooks: + - id: local-prepare-commit-msg + name: 'local prepare-commit-msg' + entry: 'Utilities/Hooks/prepare-commit-msg' + language: system + stages: [prepare-commit-msg] + - id: kw-commit-msg + name: 'kw commit-msg' + entry: 'python3 Utilities/Hooks/kw-commit-msg.py' + language: system + stages: [commit-msg] diff --git a/.pypirc.example b/.pypirc.example new file mode 100644 index 00000000..05b64161 --- /dev/null +++ b/.pypirc.example @@ -0,0 +1,23 @@ +# .pypirc.example -- DO NOT commit real credentials +# Copy to ~/.pypirc and fill in your token. +# +# Generate a token at: https://pypi.org/manage/account/token/ +# For TestPyPI: https://test.pypi.org/manage/account/token/ +# +# Alternatively, set environment variables: +# TWINE_USERNAME=__token__ +# TWINE_PASSWORD=pypi- + +[distutils] +index-servers = + pypi + testpypi + +[pypi] +username = __token__ +password = pypi-YOUR-TOKEN-HERE + +[testpypi] +repository = https://test.pypi.org/legacy/ +username = __token__ +password = pypi-YOUR-TOKEN-HERE diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 00000000..72aeff6c --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,13 @@ +version: 2 + +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +sphinx: + configuration: docs/conf.py + +python: + install: + - requirements: docs/requirements-docs.txt diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index e00ff622..00000000 --- a/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -sudo: required - -services: - - docker - -cache: - directories: - - $HOME/docker - -before_install: - - sudo pip install -U scikit-ci-addons - - ci_addons docker load-pull-save r.j3ss.co/shellcheck - -script: - - scripts/lint-shell-scripts.sh diff --git a/BuildWheelsSupport/CMakeLists.txt b/BuildWheelsSupport/CMakeLists.txt new file mode 100644 index 00000000..dbaa4a66 --- /dev/null +++ b/BuildWheelsSupport/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.26.6 FATAL_ERROR) +# NOTE: 3.26.6 is the first cmake version to support Development.SABIModule + +project(ITKPythonPackageWheels CXX) + +include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/ITKPythonPackage_Utils.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/ITKPythonPackage_BuildWheels.cmake) diff --git a/LICENSE b/BuildWheelsSupport/LICENSE similarity index 100% rename from LICENSE rename to BuildWheelsSupport/LICENSE diff --git a/scripts/WHEEL_NAMES.txt b/BuildWheelsSupport/WHEEL_NAMES.txt similarity index 89% rename from scripts/WHEEL_NAMES.txt rename to BuildWheelsSupport/WHEEL_NAMES.txt index 94ff00af..434c06c1 100644 --- a/scripts/WHEEL_NAMES.txt +++ b/BuildWheelsSupport/WHEEL_NAMES.txt @@ -4,4 +4,4 @@ itk-io itk-filtering itk-registration itk-segmentation -itk-meta \ No newline at end of file +itk-meta diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..d49e838e --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,108 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +ITKPythonPackage is a cross-platform build system for creating Python binary wheels for the Insight Toolkit (ITK) — an open-source C++ image analysis library. It builds wheels for ITK itself and for ITK external (remote) modules across Linux, macOS, and Windows (x86_64 and arm64/aarch64). + +ITK external modules require pre-built ITK artifacts. These are cached as [ITKPythonBuilds](https://github.com/InsightSoftwareConsortium/ITKPythonBuilds) releases to avoid rebuilding ITK for every module. + +## Build System + +### Running a build + +The primary entry point is `scripts/build_wheels.py`, orchestrated via pixi: + +```sh +pixi run build-itk-wheels +``` + +Or directly: +```sh +python scripts/build_wheels.py +``` + +### Environment management + +**pixi** (conda-like) manages reproducible build environments defined in `pixi.toml`. Environments are composed per-platform and per-Python-version (e.g., `manylinux228-py310`, `macosx-py311`). + +### Key environment variables (GitHub Actions compatible) + +- `ITK_PACKAGE_VERSION` — Version string for wheels +- `ITKPYTHONPACKAGE_TAG` — ITKPythonPackage version/tag to use +- `ITKPYTHONPACKAGE_ORG` — GitHub org (default: InsightSoftwareConsortium) +- `ITK_MODULE_PREQ` — Module dependencies (`org/repo@tag:org/repo@tag:...`) +- `CMAKE_OPTIONS` — Extra CMake flags +- `MANYLINUX_VERSION` — Manylinux ABI version (_2_28, _2_34, etc.) +- `MACOSX_DEPLOYMENT_TARGET` — macOS minimum deployment target + +### Linting + +```sh +pre-commit run --all-files +``` + +Shell script linting was previously via `.travis.yml`; now uses pre-commit hooks. + +## Architecture + +### Python build scripts (`scripts/`) + +Class hierarchy for platform-specific wheel building: + +- **`build_wheels.py`** — Main driver. Detects platform/arch, selects pixi environment, creates platform-specific build instance. +- **`build_python_instance_base.py`** — Abstract base class defining the shared build pipeline (download, configure, build, package). +- **`linux_build_python_instance.py`** — Linux: TBB support, `auditwheel` for manylinux compliance. +- **`macos_build_python_instance.py`** — macOS: `delocate` for dylib relocation. +- **`windows_build_python_instance.py`** — Windows: `delvewheel` for DLL bundling. + +Supporting scripts: +- **`pyproject_configure.py`** — Generates `pyproject.toml` from `pyproject.toml.in` template with platform-specific substitutions. +- **`wheel_builder_utils.py`** — Shared utilities (subprocess wrappers, path handling, env parsing). +- **`cmake_argument_builder.py`** — Builds CMake args for both direct invocation (`-DKEY=VALUE`) and scikit-build-core (`--config-setting=cmake.define.KEY=VALUE`). +- **`BuildManager.py`** — JSON-based build step tracking for resuming interrupted builds. + +### CMake layer (`cmake/`) + +- **`ITKPythonPackage_Utils.cmake`** — Utility functions for module dependency resolution, wheel-to-group mapping. +- **`ITKPythonPackage_BuildWheels.cmake`** — Wheel-specific CMake build configuration. +- **`ITKPythonPackage_SuperBuild.cmake`** — ITK + dependencies superbuild. + +### Wheel targets + +Defined in `BuildWheelsSupport/WHEEL_NAMES.txt`: itk-core, itk-numerics, itk-io, itk-filtering, itk-registration, itk-segmentation, itk-meta. + +### Build backend + +Uses **scikit-build-core**. The `pyproject.toml.in` template is the single source of truth for project metadata. + +### Conda/pixi-build integration (`packages/libitk-wrapping/`) + +The `libitk-wrapping` package is a rattler-build recipe that produces a conda package of ITK C++ with full Python wrapping artifacts. When installed in a pixi/conda environment, the build system automatically detects it and skips the expensive ITK C++ compilation (steps 01-02), reducing remote module build times from ~1-2 hours to ~15 minutes. + +- **`packages/libitk-wrapping/recipe.yaml`** — rattler-build recipe (configurable via `ITK_GIT_URL`/`ITK_GIT_TAG` env vars) +- **`packages/libitk-wrapping/build-libitk-wrapping.sh`** — Unix build script +- **`packages/libitk-wrapping/build-libitk-wrapping.bat`** — Windows build script +- **`conda-forge/`** — Prepared conda-forge staged-recipes submission + +Detection is in `build_python_instance_base.py:_detect_conda_itk()` — checks `CONDA_PREFIX` and `PIXI_ENVIRONMENT_DIR` for `lib/cmake/ITK-*/ITKConfig.cmake`. + +## Shell script entry points + +Legacy shell/PowerShell scripts are preserved for backward compatibility with existing CI workflows: +- `scripts/dockcross-manylinux-download-cache-and-build-module-wheels.sh` (Linux) +- `scripts/macpython-download-cache-and-build-module-wheels.sh` (macOS) +- `scripts/windows-download-cache-and-build-module-wheels.ps1` (Windows) + +These scripts delegate to the Python build system internally and will skip tarball downloads when a conda-installed ITK is detected. + +### Commit message convention + +This project follows the ITK commit message convention: `PREFIX: Description`. Valid prefixes: `BUG:`, `COMP:`, `DOC:`, `ENH:`, `PERF:`, `STYLE:`. Enforced via commitizen (configured in `pyproject.toml`, validated by the `commit-msg` pre-commit hook). + +## Related repositories + +- [ITK](https://github.com/InsightSoftwareConsortium/ITK) — The C++ toolkit itself +- [ITKPythonBuilds](https://github.com/InsightSoftwareConsortium/ITKPythonBuilds) — Cached ITK build artifacts +- [ITKRemoteModuleBuildTestPackageAction](https://github.com/InsightSoftwareConsortium/ITKRemoteModuleBuildTestPackageAction) — GitHub Actions reusable workflows for building/testing/packaging diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 6908545c..00000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,571 +0,0 @@ -cmake_minimum_required(VERSION 3.26.6 FATAL_ERROR) -# NOTE: 3.26.6 is the first cmake vesion to support Development.SABIModule - -project(ITKPythonPackage CXX) - -set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH}) -include(ITKPythonPackage) - -if(NOT DEFINED ITKPythonPackage_SUPERBUILD) - set(ITKPythonPackage_SUPERBUILD 1) -endif() - -if(NOT DEFINED ITKPythonPackage_WHEEL_NAME) - set(ITKPythonPackage_WHEEL_NAME "itk") -endif() -message(STATUS "SuperBuild - ITKPythonPackage_WHEEL_NAME:${ITKPythonPackage_WHEEL_NAME}") - -option(ITKPythonPackage_USE_TBB "Build and use oneTBB in the ITK python package" ON) - -if(ITKPythonPackage_SUPERBUILD) - - #----------------------------------------------------------------------------- - #------------------------------------------------------ - #---------------------------------- - # ITKPythonPackage_SUPERBUILD: ON - #---------------------------------- - #------------------------------------------------------ - #----------------------------------------------------------------------------- - - # Avoid "Manually-specified variables were not used by the project" warnings. - ipp_unused_vars(${PYTHON_VERSION_STRING} ${SKBUILD}) - - set(ep_common_cmake_cache_args ) - if(NOT CMAKE_CONFIGURATION_TYPES) - list(APPEND ep_common_cmake_cache_args - -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} - ) - endif() - set(ep_download_extract_timestamp_arg ) - if(CMAKE_VERSION VERSION_EQUAL "3.24" OR CMAKE_VERSION VERSION_GREATER "3.24") - # See https://cmake.org/cmake/help/latest/policy/CMP0135.html - set(ep_download_extract_timestamp_arg DOWNLOAD_EXTRACT_TIMESTAMP 1) - endif() - - #----------------------------------------------------------------------------- - # Options - - # When building different "flavor" of ITK python packages on a given platform, - # explicitly setting the following options allow to speed up package generation by - # re-using existing resources. - # - # ITK_SOURCE_DIR: Path to an existing source directory - # - - option(ITKPythonPackage_BUILD_PYTHON "Build ITK python module" ON) - mark_as_advanced(ITKPythonPackage_BUILD_PYTHON) - - if(CMAKE_OSX_DEPLOYMENT_TARGET) - list(APPEND ep_common_cmake_cache_args - -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${CMAKE_OSX_DEPLOYMENT_TARGET}) - endif() - if(CMAKE_OSX_ARCHITECTURES) - list(APPEND ep_common_cmake_cache_args - -DCMAKE_OSX_ARCHITECTURES:STRING=${CMAKE_OSX_ARCHITECTURES}) - endif() - - if(CMAKE_MAKE_PROGRAM) - list(APPEND ep_common_cmake_cache_args - -DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}) - endif() - - #----------------------------------------------------------------------------- - # compile with multiple processors - include(ProcessorCount) - ProcessorCount(NPROC) - if(NOT NPROC EQUAL 0) - set( ENV{MAKEFLAGS} "-j${NPROC}" ) - endif() - - #----------------------------------------------------------------------------- - include(ExternalProject) - - set(ITK_REPOSITORY "https://github.com/InsightSoftwareConsortium/ITK.git") - - # release branch, 2026-03-10 - set(ITK_GIT_TAG "c6e1c1be6a86236cbb812bd71eec5a4df9b1353c") - - #----------------------------------------------------------------------------- - # A separate project is used to download ITK, so that it can reused - # when building different "flavor" of ITK python packages - - message(STATUS "SuperBuild -") - message(STATUS "SuperBuild - ITK-source-download") - - # Sanity checks - if(DEFINED ITK_SOURCE_DIR AND NOT EXISTS ${ITK_SOURCE_DIR}) - message(FATAL_ERROR "ITK_SOURCE_DIR variable is defined but corresponds to nonexistent directory") - endif() - - if(ITKPythonPackage_USE_TBB) - if(ITK_SOURCE_DIR) - set(TBB_DIR "${ITK_SOURCE_DIR}/../oneTBB-prefix/lib/cmake/TBB") - else() - set(TBB_DIR "${CMAKE_BINARY_DIR}/../oneTBB-prefix/lib/cmake/TBB") - endif() - set(tbb_args ) - if(ITKPythonPackage_USE_TBB) - set(tbb_args - -DModule_ITKTBB:BOOL=ON - -DTBB_DIR:PATH=${TBB_DIR} - ) - endif() - - set(tbb_cmake_cache_args) - if(CMAKE_OSX_DEPLOYMENT_TARGET) - list(APPEND tbb_cmake_cache_args - -DCMAKE_CXX_OSX_DEPLOYMENT_TARGET_FLAG:STRING="-mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}" - -DCMAKE_C_OSX_DEPLOYMENT_TARGET_FLAG:STRING="-mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}" - ) - endif() - - ExternalProject_add(oneTBB - URL https://github.com/oneapi-src/oneTBB/archive/refs/tags/v2022.2.0.tar.gz - URL_HASH SHA256=f0f78001c8c8edb4bddc3d4c5ee7428d56ae313254158ad1eec49eced57f6a5b - CMAKE_ARGS - -DTBB_TEST:BOOL=OFF - -DCMAKE_BUILD_TYPE:STRING=Release - -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}/../oneTBB-prefix - -DCMAKE_INSTALL_LIBDIR:STRING=lib # Skip default initialization by GNUInstallDirs CMake module - ${ep_common_cmake_cache_args} - ${tbb_cmake_cache_args} - ${ep_download_extract_timestamp_arg} - -DCMAKE_BUILD_TYPE:STRING=Release - BUILD_BYPRODUCTS "${TBB_DIR}/TBBConfig.cmake" - USES_TERMINAL_DOWNLOAD 1 - USES_TERMINAL_UPDATE 1 - USES_TERMINAL_CONFIGURE 1 - USES_TERMINAL_BUILD 1 - ) - message(STATUS "SuperBuild - TBB: Enabled") - message(STATUS "SuperBuild - TBB_DIR: ${TBB_DIR}") - endif() - set(tbb_depends "") - if(ITKPythonPackage_USE_TBB) - set(tbb_depends oneTBB) - endif() - - - if(NOT DEFINED ITK_SOURCE_DIR) - - set(ITK_SOURCE_DIR ${CMAKE_BINARY_DIR}/ITK) - - ExternalProject_add(ITK-source-download - SOURCE_DIR ${ITK_SOURCE_DIR} - GIT_REPOSITORY ${ITK_REPOSITORY} - GIT_TAG ${ITK_GIT_TAG} - USES_TERMINAL_DOWNLOAD 1 - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - DEPENDS "${tbb_depends}" - ) - set(proj_status "") - - else() - - ipp_ExternalProject_Add_Empty( - ITK-source-download - "" - ) - set(proj_status " (REUSE)") - - endif() - - message(STATUS "SuperBuild - ITK_SOURCE_DIR: ${ITK_SOURCE_DIR}") - message(STATUS "SuperBuild - ITK-source-download[OK]${proj_status}") - - #----------------------------------------------------------------------------- - if(NOT ITKPythonPackage_BUILD_PYTHON) - return() - endif() - - #----------------------------------------------------------------------------- - # Search for python interpreter and libraries - - message(STATUS "SuperBuild -") - message(STATUS "SuperBuild - Searching for python") - - # Sanity checks - if(DEFINED Python3_INCLUDE_DIR AND NOT EXISTS ${Python3_INCLUDE_DIR}) - message(FATAL_ERROR "Python3_INCLUDE_DIR variable is defined but corresponds to nonexistent directory") - endif() - if(DEFINED Python3_LIBRARY AND NOT EXISTS ${Python3_LIBRARY}) - message(FATAL_ERROR "Python3_LIBRARY variable is defined but corresponds to nonexistent file") - endif() - if(DEFINED Python3_EXECUTABLE AND NOT EXISTS ${Python3_EXECUTABLE}) - message(FATAL_ERROR "Python3_EXECUTABLE variable is defined but corresponds to nonexistent file") - endif() - if(DEFINED DOXYGEN_EXECUTABLE AND NOT EXISTS ${DOXYGEN_EXECUTABLE}) - message(FATAL_ERROR "DOXYGEN_EXECUTABLE variable is defined but corresponds to nonexistent file") - endif() - - if(NOT DEFINED Python3_INCLUDE_DIR - OR NOT DEFINED Python3_LIBRARY - OR NOT DEFINED Python3_EXECUTABLE) - - find_package(Python3 COMPONENTS Interpreter Development) - if(NOT Python3_EXECUTABLE AND _Python3_EXECUTABLE) - set(Python3_EXECUTABLE ${_Python3_EXECUTABLE} CACHE INTERNAL - "Path to the Python interpreter" FORCE) - endif() - endif() - if(NOT DEFINED DOXYGEN_EXECUTABLE) - find_package(Doxygen REQUIRED) - endif() - - message(STATUS "SuperBuild - Python3_INCLUDE_DIR: ${Python3_INCLUDE_DIR}") - message(STATUS "SuperBuild - Python3_INCLUDE_DIRS: ${Python3_INCLUDE_DIRS}") - message(STATUS "SuperBuild - Python3_LIBRARY: ${Python3_LIBRARY}") - message(STATUS "SuperBuild - Python3_EXECUTABLE: ${Python3_EXECUTABLE}") - message(STATUS "SuperBuild - Searching for python[OK]") - message(STATUS "SuperBuild - DOXYGEN_EXECUTABLE: ${DOXYGEN_EXECUTABLE}") - - # CMake configuration variables to pass to ITK's build - set(ep_itk_cmake_cache_args "") - foreach(var - BUILD_SHARED_LIBS - ITK_BUILD_DEFAULT_MODULES - ) - if(DEFINED ${var}) - list(APPEND ep_itk_cmake_cache_args "-D${var}=${${var}}") - endif() - endforeach() - function(cached_variables RESULTVAR PATTERN) - get_cmake_property(variables CACHE_VARIABLES) - set(result) - foreach(variable ${variables}) - if(${variable} AND variable MATCHES "${PATTERN}") - list(APPEND result "-D${variable}=${${variable}}") - endif() - endforeach() - set(${RESULTVAR} ${result} PARENT_SCOPE) - endfunction() - cached_variables(itk_pattern_cached_vars "^(ITK_WRAP_)|(ITKGroup_)|(Module_)") - list(APPEND ep_itk_cmake_cache_args ${itk_pattern_cached_vars}) - # Todo, also pass all Module_* variables - message(STATUS "ITK CMake Cache Args - ${ep_itk_cmake_cache_args}") - #----------------------------------------------------------------------------- - # ITK: This project builds ITK and associated Python modules - - option(ITKPythonPackage_ITK_BINARY_REUSE "Reuse provided ITK_BINARY_DIR without configuring or building ITK" OFF) - - set(ITK_BINARY_DIR "${CMAKE_BINARY_DIR}/ITKb" CACHE PATH "ITK build directory") - - message(STATUS "SuperBuild -") - message(STATUS "SuperBuild - ITK => Requires ITK-source-download") - message(STATUS "SuperBuild - ITK_BINARY_DIR: ${ITK_BINARY_DIR}") - - if(NOT ITKPythonPackage_ITK_BINARY_REUSE) - - set(_stamp "${CMAKE_BINARY_DIR}/ITK-prefix/src/ITK-stamp/ITK-configure") - if(EXISTS ${_stamp}) - execute_process(COMMAND ${CMAKE_COMMAND} -E remove ${_stamp}) - message(STATUS "SuperBuild - Force re-configure removing ${_stamp}") - endif() - - set(install_component_per_module OFF) - if(NOT ITKPythonPackage_WHEEL_NAME STREQUAL "itk") - set(install_component_per_module ON) - endif() - - ExternalProject_add(ITK - DOWNLOAD_COMMAND "" - SOURCE_DIR ${ITK_SOURCE_DIR} - BINARY_DIR ${ITK_BINARY_DIR} - PREFIX "ITKp" - CMAKE_ARGS - -DBUILD_TESTING:BOOL=OFF - -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_INSTALL_PREFIX} - -DPY_SITE_PACKAGES_PATH:PATH=${CMAKE_INSTALL_PREFIX} - -DWRAP_ITK_INSTALL_COMPONENT_IDENTIFIER:STRING=PythonWheel - -DWRAP_ITK_INSTALL_COMPONENT_PER_MODULE:BOOL=${install_component_per_module} - -DITK_LEGACY_SILENT:BOOL=ON - -DITK_WRAP_PYTHON:BOOL=ON - -DDOXYGEN_EXECUTABLE:FILEPATH=${DOXYGEN_EXECUTABLE} - -DPython3_INCLUDE_DIR:PATH=${Python3_INCLUDE_DIR} - -DPython3_LIBRARY:FILEPATH=${Python3_LIBRARY} - -DPython3_EXECUTABLE:FILEPATH=${Python3_EXECUTABLE} - ${ep_common_cmake_cache_args} - ${tbb_args} - ${ep_itk_cmake_cache_args} - ${ep_download_extract_timestamp_arg} - USES_TERMINAL_DOWNLOAD 1 - USES_TERMINAL_UPDATE 1 - USES_TERMINAL_CONFIGURE 1 - USES_TERMINAL_BUILD 1 - INSTALL_COMMAND "" - ) - set(proj_status "") - - else() - - # Sanity checks - if(NOT EXISTS "${ITK_BINARY_DIR}/CMakeCache.txt") - message(FATAL_ERROR "ITKPythonPackage_ITK_BINARY_REUSE is ON but ITK_BINARY_DIR variable is not associated with an ITK build directory. [ITK_BINARY_DIR:${ITK_BINARY_DIR}]") - endif() - - ipp_ExternalProject_Add_Empty( - ITK - "" - ) - set(proj_status " (REUSE)") - - endif() - ExternalProject_Add_StepDependencies(ITK download ITK-source-download) - - message(STATUS "SuperBuild - ITK[OK]${proj_status}") - - #----------------------------------------------------------------------------- - # ITKPythonPackage: This project adds install rules for the "RuntimeLibraries" - # components associated with the ITK project. - - message(STATUS "SuperBuild -") - message(STATUS "SuperBuild - ${PROJECT_NAME} => Requires ITK") - - ExternalProject_add(${PROJECT_NAME} - SOURCE_DIR ${CMAKE_SOURCE_DIR} - BINARY_DIR ${CMAKE_BINARY_DIR}/${PROJECT_NAME}-build - DOWNLOAD_COMMAND "" - UPDATE_COMMAND "" - CMAKE_CACHE_ARGS - -DITKPythonPackage_SUPERBUILD:BOOL=0 - -DITK_BINARY_DIR:PATH=${ITK_BINARY_DIR} - -DITK_SOURCE_DIR:PATH=${ITK_SOURCE_DIR} - -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_INSTALL_PREFIX} - -DITKPythonPackage_WHEEL_NAME:STRING=${ITKPythonPackage_WHEEL_NAME} - -DITKPythonPackage_USE_TBB:BOOL=${ITKPythonPackage_USE_TBB} - ${ep_common_cmake_cache_args} - USES_TERMINAL_CONFIGURE 1 - INSTALL_COMMAND "" - DEPENDS ITK - ) - - install(SCRIPT ${CMAKE_BINARY_DIR}/${PROJECT_NAME}-build/cmake_install.cmake) - - message(STATUS "SuperBuild - ${PROJECT_NAME}[OK]") - -else() - - #----------------------------------------------------------------------------- - #------------------------------------------------------ - #---------------------------------- - # ITKPythonPackage_SUPERBUILD: OFF - #---------------------------------- - #------------------------------------------------------ - #----------------------------------------------------------------------------- - - set(components "PythonWheelRuntimeLibraries") - if(NOT ITKPythonPackage_WHEEL_NAME STREQUAL "itk") - - message(STATUS "ITKPythonPackage_WHEEL_NAME: ${ITKPythonPackage_WHEEL_NAME}") - - # Extract ITK group name from wheel name - message(STATUS "") - set(msg "Extracting ITK_WHEEL_GROUP") - message(STATUS ${msg}) - ipp_wheel_to_group(${ITKPythonPackage_WHEEL_NAME} ITK_WHEEL_GROUP) - message(STATUS "${msg} - done [${ITK_WHEEL_GROUP}]") - - # - # Considering that - # - # * Every ITK module is associated with exactly one ITK group. - # * ITK module dependencies are specified independently of ITK groups - # - # we semi-arbitrarily defined a collection of wheels (see ``ITK_WHEEL_GROUPS``) - # that will roughly bundle the modules associated with each group. - # - # Based on the module dependency graph, the code below will determine which module - # should be packaged in which wheel. - # - - # List of ITK wheel groups - set(ITK_WHEEL_GROUPS "") - file(STRINGS "${CMAKE_SOURCE_DIR}/scripts/WHEEL_NAMES.txt" ITK_WHEELS REGEX "^itk-.+") - foreach(wheel_name IN LISTS ITK_WHEELS) - ipp_wheel_to_group(${wheel_name} group) - list(APPEND ITK_WHEEL_GROUPS ${group}) - endforeach() - - # Define below a reasonable dependency graph for ITK groups - set(ITK_GROUP_Core_DEPENDS) - set(ITK_GROUP_IO_DEPENDS Core) - set(ITK_GROUP_Numerics_DEPENDS Core) - set(ITK_GROUP_Filtering_DEPENDS Numerics) - set(ITK_GROUP_Segmentation_DEPENDS Filtering) - set(ITK_GROUP_Registration_DEPENDS Filtering) - set(ITK_GROUP_Video_DEPENDS Core) - - # ITK is needed to retrieve ITK module information - set(ITK_DIR ${ITK_BINARY_DIR}) - find_package(ITK REQUIRED) - set(CMAKE_MODULE_PATH ${ITK_CMAKE_DIR} ${CMAKE_MODULE_PATH}) - - # Sort wheel groups - include(TopologicalSort) - topological_sort(ITK_WHEEL_GROUPS ITK_GROUP_ _DEPENDS) - - # Set ``ITK_MODULE__DEPENDS`` variables - # - # Notes: - # - # * ``_DEPENDS`` variables are set after calling ``find_package(ITK REQUIRED)`` - # - # * This naming convention corresponds to what is used internally in ITK and allow - # to differentiate with variable like ``ITK_GROUP__DEPENDS`` set above. - # - foreach(module IN LISTS ITK_MODULES_ENABLED) - set(ITK_MODULE_${module}_DEPENDS "${${module}_DEPENDS}") - endforeach() - - # Set ``ITK_MODULE__DEPENDEES`` variables - foreach(module IN LISTS ITK_MODULES_ENABLED) - ipp_get_module_dependees(${module} ITK_MODULE_${module}_DEPENDEES) - endforeach() - - # Set ``ITK_GROUPS`` variable - file(GLOB group_dirs "${ITK_SOURCE_DIR}/Modules/*") - set(ITK_GROUPS ) - foreach(dir IN LISTS group_dirs) - file(RELATIVE_PATH group "${ITK_SOURCE_DIR}/Modules" "${dir}") - if(NOT IS_DIRECTORY "${dir}" OR "${group}" MATCHES "^External$") - continue() - endif() - list(APPEND ITK_GROUPS ${group}) - endforeach() - message(STATUS "") - message(STATUS "ITK_GROUPS:${ITK_GROUPS}") - - # Set ``ITK_MODULE__GROUP`` variables - foreach(group IN LISTS ITK_GROUPS) - file( GLOB_RECURSE _${group}_module_files ${ITK_SOURCE_DIR}/Modules/${group}/itk-module.cmake ) - foreach( _module_file ${_${group}_module_files} ) - file(READ ${_module_file} _module_file_content) - string( REGEX MATCH "itk_module[ \n]*(\\([ \n]*)([A-Za-z0-9]*)" _module_name ${_module_file_content} ) - set(_module_name ${CMAKE_MATCH_2}) - list( APPEND _${group}_module_list ${_module_name} ) - set(ITK_MODULE_${_module_name}_GROUP ${group}) - endforeach() - endforeach() - - # Initialize ``ITK_WHEEL__MODULES`` variables that will contain list of modules - # to package in each wheel. - foreach(group IN LISTS ITK_WHEEL_GROUPS) - set(ITK_WHEEL_${group}_MODULES "") - endforeach() - - # Configure table display - set(row_widths 40 20 20 10 90 12) - set(row_headers MODULE_NAME MODULE_GROUP WHEEL_GROUP IS_LEAF MODULE_DEPENDEES_GROUPS IS_WRAPPED) - message(STATUS "") - ipp_display_table_row("${row_headers}" "${row_widths}") - - # Update ``ITK_WHEEL__MODULES`` variables - foreach(module IN LISTS ITK_MODULES_ENABLED) - - ipp_is_module_leaf(${module} leaf) - set(dependees_groups) - if(NOT leaf) - set(dependees "") - ipp_recursive_module_dependees(${module} dependees) - foreach(dep IN LISTS dependees) - list(APPEND dependees_groups ${ITK_MODULE_${dep}_GROUP}) - endforeach() - if(dependees_groups) - list(REMOVE_DUPLICATES dependees_groups) - endif() - endif() - - # Filter out group not associated with a wheel - set(dependees_wheel_groups) - foreach(group IN LISTS dependees_groups) - list(FIND ITK_WHEEL_GROUPS ${group} _index) - if(_index EQUAL -1) - continue() - endif() - list(APPEND dependees_wheel_groups ${group}) - endforeach() - - set(wheel_group) - list(LENGTH dependees_wheel_groups _length) - - # Sanity check - if(leaf AND _length GREATER 0) - message(FATAL_ERROR "leaf module should not module depending on them !") - endif() - - if(_length EQUAL 0) - set(wheel_group "${ITK_MODULE_${module}_GROUP}") - elseif(_length EQUAL 1) - # Since packages depending on this module belong to one group, also package this module - set(wheel_group "${dependees_wheel_groups}") - elseif(_length GREATER 1) - # If more than one group is associated with the dependees, package the module in the - # "common ancestor" group. - set(common_ancestor_index 999999) - foreach(g IN LISTS dependees_wheel_groups) - list(FIND ITK_WHEEL_GROUPS ${g} _index) - if(NOT _index EQUAL -1 AND _index LESS common_ancestor_index) - set(common_ancestor_index ${_index}) - endif() - endforeach() - list(GET ITK_WHEEL_GROUPS ${common_ancestor_index} wheel_group) - endif() - - set(wheel_group_display ${wheel_group}) - - # XXX Hard-coded dispatch - if(module STREQUAL "ITKBridgeNumPy") - set(new_wheel_group "Core") - set(wheel_group_display "${new_wheel_group} (was ${wheel_group})") - set(wheel_group ${new_wheel_group}) - endif() - if(module STREQUAL "ITKVTK") - set(new_wheel_group "Core") - set(wheel_group_display "${new_wheel_group} (was ${wheel_group})") - set(wheel_group ${new_wheel_group}) - endif() - - # Associate module with a wheel - list(APPEND ITK_WHEEL_${wheel_group}_MODULES ${module}) - - # Display module info - ipp_is_module_python_wrapped(${module} is_wrapped) - ipp_list_to_string("^^" "${dependees_groups}" dependees_groups_str) - set(row_values "${module};${ITK_MODULE_${module}_GROUP};${wheel_group_display};${leaf};${dependees_groups_str};${is_wrapped}") - ipp_display_table_row("${row_values}" "${row_widths}") - - endforeach() - - # Set list of components to install - set(components "") - foreach(module IN LISTS ITK_WHEEL_${ITK_WHEEL_GROUP}_MODULES) - list(APPEND components ${module}PythonWheelRuntimeLibraries) - endforeach() - - endif() - - if(MSVC AND ITKPythonPackage_WHEEL_NAME STREQUAL "itk-core") - message(STATUS "Adding install rules for compiler runtime libraries") - # Put the runtime libraries next to the "itk/_*.pyd" C-extensions so they - # are found. - set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION "itk") - include(InstallRequiredSystemLibraries) - endif() - - #----------------------------------------------------------------------------- - # Install ITK components - message(STATUS "Adding install rules for components:") - foreach(component IN LISTS components) - message(STATUS " ${component}") - install(CODE " -unset(CMAKE_INSTALL_COMPONENT) -set(COMPONENT \"${component}\") -set(CMAKE_INSTALL_DO_STRIP 1) -include(\"${ITK_BINARY_DIR}/cmake_install.cmake\") -unset(CMAKE_INSTALL_COMPONENT) -") - endforeach() - -endif() diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..719705d1 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,73 @@ +# Contributing to ITKPythonPackage + +## Getting Started + +Clone the repository and install the pre-commit hooks: + +```bash +git clone https://github.com/InsightSoftwareConsortium/ITKPythonPackage.git +cd ITKPythonPackage +```` + +Install [Pixi](https://pixi.sh) for managing the build environment: + +```bash +curl -fsSL https://pixi.sh/install.sh | bash +pixi install +``` + +Install pre-commit hooks + +```bash +pixi run pre-commit-install +# optionally run pre-commit hooks +pixi run pre-commit-run +``` + + +## Development Workflow + +### Code Style + +Pre-commit hooks enforce all formatting and linting automatically on commit: + +- **Python**: Black (formatting), Ruff (linting + import sorting) +- **Shell**: ShellCheck (linting), shfmt (formatting) +- **TOML**: Taplo (formatting) + +Run against all files manually: + +```bash +pre-commit run --all-files +``` + +### Commit Messages + +This project uses [Conventional Commits](https://www.conventionalcommits.org), enforced by Commitizen: + +``` +feat: add support for Python 3.12 wheels +fix: correct cmake args not propagating to module builds +chore: update pre-commit hook versions +docs: clarify aarch64 build requirements +``` + +Commitizen will reject commits that don't follow this format. + +### Building Docs + +```bash +pip install -r docs/requirements-docs.txt +sphinx-build -W -b html docs docs/_build/html +``` + +## Submitting a Pull Request + +1. Create a branch from `main` +2. Make your changes and ensure `pre-commit run --all-files` passes +3. Open a PR, fill out the template, including which platforms you tested on +4. CI will run pre-commit checks automatically + +## Questions + +For build questions or general ITK support, use the [ITK Discourse forum](https://discourse.itk.org). diff --git a/README.md b/README.md index 052a849a..3b42c7de 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # ITK Python Package This project configures pyproject.toml files and manages environmental -variables needed to build ITK Python binary wheels on MacOS, Linux, and Windows platforms. -Scripts are available for both [ITK infrastructure](https://github.com/insightSoftwareConsortium/ITK) and +variables needed to build ITK Python binary wheels on macOS, Linux, and Windows platforms. +Scripts are available for both [ITK infrastructure](https://github.com/insightSoftwareConsortium/ITK) and ITK external module Python packages. The Insight Toolkit (ITK) is an open-source, cross-platform system that provides developers @@ -12,86 +12,327 @@ or at the [ITK GitHub homepage](https://github.com/insightSoftwareConsortium/ITK ## Table of Contents -- [Using ITK Python Packages](#using-itk-python-packages) -- [Building with ITKPythonPackage](#building-with-itkpythonpackage) +- [Building Remote Modules with ITKPythonPackage](#building-remote-modules-with-itkpythonpackage) +- [Building ITK Python Wheels](#building-itk-python-wheels) - [Frequently Asked Questions](#frequently-asked-questions) - [Additional Information](#additional-information) -## Using ITK Python Packages (pre-built, or locally built) +## Building Remote Modules with ITKPythonPackage -ITKPythonPackage scripts can be used to produce [Python](https://www.python.org/) packages -for ITK and ITK external modules. The resulting packages can be -hosted on the [Python Package Index (PyPI)](https://pypi.org/) -for easy distribution. +ITK reusable workflows are available to build and package Python wheels as +part of Continuous Integration (CI) via GitHub Actions runners. +Those workflows can handle the overhead of fetching, configuring, and +running ITKPythonPackage build scripts for most ITK external modules. +See [ITKRemoteModuleBuildTestPackageAction](https://github.com/InsightSoftwareConsortium/ITKRemoteModuleBuildTestPackageAction) +for more information. + +> [!NOTE] +> When using`ITKRemoteModuleBuildTestPackageAction` in your remote module, you can specify the `itk-python-package-org` and `itk-python-package-tag` to build with. + +For special cases where ITK reusable workflows are not a good fit, +ITKPythonPackage scripts can be directly used to build Python wheels +to target Windows, Linux, and macOS platforms. See +below or the [ITKPythonPackage ReadTheDocs](https://itkpythonpackage.readthedocs.io/en/latest/Build_ITK_Module_Python_packages.html) +documentation for more information on building wheels by hand. + +## Building ITK Python Wheels + +### Do You Actually Need to Build ITK? + +Most users do not need to build ITK from source. -### Installation of pre-built packages +Pre-built ITK binaries are available as downloadable tarballs and the provided download-and-build shell scripts will fetch them automatically. -To install baseline ITK Python packages: +You may only need to build ITK yourself if you: +- Have a local ITK with custom patches or bug fixes not yet in a release +- Need to build against a specific unreleased commit +- Are developing ITK core itself -```sh -> pip install itk +If none of the above apply to you, you may download an existing build of ITK from ITK's repository for [ITK Python Builds](https://github.com/InsightSoftwareConsortium/ITKPythonBuilds/releases). **Or**, use the download-and-build script seen in the [Building Remote Module Wheels](#building-remote-module-wheels) section below. + +For more control over your builds, skip to [The Build Process](#the-build-process) + +--- + +### Prerequisites + +- Python 3.10 or later +- Git +- Docker (for manylinux builds) +- [Pixi](https://pixi.sh) package manager + +**Install Pixi:** +```bash +# Linux or Mac +curl -fsSL https://pixi.sh/install.sh | bash + +# Windows +powershell -ExecutionPolicy Bypass -c "irm -useb https://pixi.sh/install.ps1 | iex" ``` -To install ITK external module packages: +**Clone the repo:** +```bash +git clone https://github.com/InsightSoftwareConsortium/ITKPythonPackage.git +cd ITKPythonPackage +``` + +--- + +### Building Remote Module Wheels + +#### The Build Process + +The build process calls `build_wheels.py`, which runs up to 7 steps: + +1. Build SuperBuild support components +2. Build ITK C++ with Python wrapping +3. Build wheels for ITK C++ +4. Fix up wheels if needed +5. Import test +6. *(optional)* Build a remote module against the ITK build +7. *(optional)* Build an ITK tarball cache -```sh -> pip install itk- +> [!NOTE] +> When using the download-and-build scripts, steps 2–3 are skipped because the pre-built cache covers them. + +You can invoke the `build_wheels.py` script directly for more control shown below + +Available pixi platform build environments: + +| Platform | Architectures | Python Versions | +|----------|---------------|-----------------| +| `linux` | x86_64, aarch64 | py310, py311 | +| `manylinux228` | x86_64, aarch64 | py310, py311 | +| `macosx` | x86_64, arm64 | py310, py311 | +| `windows` | x86_64 | py310, py311 | + + +```bash +# Building ITK Python Wheels on macOS for ITK v6.0b01 +pixi run python3 scripts/build_wheels.py \ + --platform-env macosx-py310 \ + --itk-git-tag v6.0b01 \ + --no-build-itk-tarball-cache ``` -### Using ITK in Python scripts +Key options: + +| Option | Description | Example | +|----------------------------------|----------------------------------------------|-------------------------------| +| `--platform-env` | Target platform and Python version | `macosx-py310` | +| `--build-dir-root` | Location for build artifacts | `/tmp/ITKPythonPackage-build` | +| `--itk-git-tag` | ITK version/branch/commit to use | `0ffcaed`, `main`, `v6.0b01` | +| `--itk-package-version` | PEP440 version string for wheels | `v6.0b01` | +| `--manylinux-version` | Manylinux standard version | `_2_28` | +| `--module-source-dir` | Path to remote module to build | `/path/to/module` | +| `--itk-module-deps` | Remote module dependencies | `Mod1@tag:Mod2@tag` | +| `--module-dependencies-root-dir` | Root directory for module dependencies | `./dependencies` | +| `--itk-source-dir` | Path to ITK source (use local development) | `/path/to/ITK` | +| `--cleanup` | Leave temporary build files after completion | (flag) | +| `--no-build-itk-tarball-cache` | Skip tarball generation (default) | (flag) | +| `--no-skip-itk-build` | Don't skip ITK build step (default | (flag) | +| `--no-skip-itk-wheel-build` | Don't skip the ITK wheel build step (default) | (flag) | -```python - import itk - import sys - input_filename = sys.argv[1] - output_filename = sys.argv[2] +Run `pixi run python3 scripts/build_wheels.py --help` for the full option list. - image = itk.imread(input_filename) +> [!NOTE] +> Building ITK from source can take 1-2 hours on typical hardware. Once complete, use `--build-itk-tarball-cache` to save the result and avoid rebuilding. - median = itk.median_image_filter(image, radius=2) +To use the scripts that take care of the build for you, see this section: - itk.imwrite(median, output_filename) +
+Download-and-Build Remote Module Builds + +This is the same process as used in the GitHub Actions CI/CD + +```bash +cd ITKRemoteModule ``` -### Other Resources for Using ITK in Python +#### Linux (manylinux) -See also the [ITK Python Quick Start -Guide](https://itkpythonpackage.readthedocs.io/en/master/Quick_start_guide.html). -There are also many [downloadable examples on the ITK examples website](https://examples.itk.org/search.html?q=Python). +Use `dockcross-manylinux-download-cache-and-build-module-wheels.sh`. This script: +1. Downloads the pre-built ITK binary tarball for your platform +2. Extracts it to a local build directory +3. Calls `dockcross-manylinux-build-module-wheels.sh` to build the module wheels inside a manylinux Docker container -For more information on ITK's Python wrapping, [an introduction is -provided in the ITK Software -Guide](https://itk.org/ITKSoftwareGuide/html/Book1/ITKSoftwareGuide-Book1ch3.html#x32-420003.7). +Run from your ITK external module root: +```bash +bash dockcross-manylinux-download-cache-and-build-module-wheels.sh cp310 +``` -## Building with ITKPythonPackage +> [!NOTE] +> Omit the Python version argument (e.g. `cp310`) to build for all default versions (cp310 and cp311). -ITK reusable workflows are available to build and package Python wheels as -part of Continuous Integration (CI) via Github Actions runners. -Those workflows can handle the overhead of fetching, configuring, and -running ITKPythonPackage build scripts for most ITK external modules. -See [ITKRemoteModuleBuildTestPackageAction](https://github.com/InsightSoftwareConsortium/ITKRemoteModuleBuildTestPackageAction) -for more information. +#### macOS + +Use `macpython-download-cache-and-build-module-wheels.sh`. This script: +1. Installs required tools (aria2, zstd, gnu-tar) via Pixi if not present +2. Downloads and extracts the macOS ITK binary tarball +3. Builds your module wheels for each requested Python version + +Run from your module root: +```bash +bash macpython-download-cache-and-build-module-wheels.sh 3.10 +``` + +#### Windows + +Use `windows-download-cache-and-build-module-wheels.ps1`. This script: +1. Installs required tools (git, aria2) via Pixi if not present +2. Downloads and extracts the Windows ITK binary zip file +3. Builds your module wheels for each requested Python version + +Run from your module root: +```powershell +.\windows-download-cache-and-build-module-wheels.ps1 3.11 +``` -For special cases where ITK reusable workflows are not a good fit, -ITKPythonPackage scripts can be directly used to build Python wheels -to target Windows, Linux, and MacOS platforms. See -[ITKPythonPackage ReadTheDocs](https://itkpythonpackage.readthedocs.io/en/master/Build_ITK_Module_Python_packages.html) -documentation for more information on building wheels by hand. +#### Output + +Finished wheels are placed in `/dist/`. + +
+ + +To see how to build wheels for your version of ITK see this section: + +
+Building ITK from Source + +If you have a local ITK with custom patches, a bug fix not yet released, or you're developing ITK core itself. Build as follows + +Pass `--itk-source-dir` pointing to your local ITK clone. `build_wheels.py` will build ITK from that source instead of re-cloning. + +#### manylinux — building ITK from source + +Use `dockcross-manylinux-build-wheels.sh` directly (skips the download step): + +```bash +ITK_SOURCE_DIR=/path/to/your/ITK \ +bash scripts/dockcross-manylinux-build-wheels.sh cp310 +``` + +Key environment variables: + +| Variable | Default | Description | +|----------|-----------------------------------------|-------------| +| `ITK_GIT_TAG` | `main` | ITK branch/tag/commit to build | +| `ITK_SOURCE_DIR` | `/ITKPythonPackage-build/ITK` | Path to local ITK source (skips git clone) | +| `MANYLINUX_VERSION` | `_2_28` | Manylinux standard to target | +| `IMAGE_TAG` | `20250913-6ea98ba` | Dockcross image tag | + +#### Linux/macOS/Windows — building ITK from source + +Use `build_wheels.py` directly with `--itk-source-dir`: + +```bash +# Building on macOS with a specific git tag +pixi run python3 scripts/build_wheels.py \ + --platform-env macosx-py310 \ + --itk-source-dir /path/to/your/ITK \ + --itk-git-tag my-bugfix-branch \ + --no-build-itk-tarball-cache \ + --build-dir-root /tmp/itk-build +``` + +Add `--build-itk-tarball-cache` if you want to save the result as a reusable tarball. + +
+ +To see how to build ITK Python Build Caches, see this section: + +
+Building ITK Python Caches + +#### GitHub Compatible Caches + +To build the caches compatible with GitHub Actions CI and the ITKPythonBuilds repository. You can run: + +On Linux and macOS systems +```bash +bash scripts/make_tarballs.sh # py310 (optionally add specific version of Python) +``` + +On Windows systems +```powershell +.\scripts\make_windows_zip.ps1 # py310 (optionally add specific version of Python) +``` + +> [!IMPORTANT] +> Build caches embed absolute paths. If you extract a tarball to a different path than it was built with, CMake will fail. Standard build paths for CI/CD are: +> - manylinux (Docker): `/work/ITKPythonPackage-build` +> - macOS: `/Users/svc-dashboard/D/P/ITKPythonPackage-build` +> - Windows: `C:\BDR` +> +> This script ensures you are building with the correct conventions + +#### Local Caches + +To build caches for local use, you can run the `build_wheels.py` script with the `--build-itk-tarball-cache` + +#### Publish Tarball Caches + +To publish the tarball caches to a GitHub Release, you can run: + +> [!NOTE] +> This requires the `GH_TOKEN` environment variable to be set or `gh auth login` to have been run beforehand. +> Tarballs are expected in the parent directory of `--build-dir-root` (POSIX `.tar.zst`) or inside it (Windows `.zip`). + +```bash +pixi run -e publish publish-tarball-cache --itk-package-version v6.0b02 --build-dir-root /path/to/build/root +``` + +Users can also specify the GitHub repository to publish to using `--repo` (defaults to ITKPythonBuilds) and +`--create-release` to create the release if it does not already exist. + +
+ +To see how to publish wheels see this section: + +
+Publishing Wheels +This repository contains a script for publishing wheels to PyPI and TestPyPI. + +The script can be run with the pixi environment as such: + +> [!NOTE] +> This script assumes you have the `TWINE_USERNAME` and `TWINE_PASSWORD` environment variables set or the +> `.pypirc` file configured on your machine. An example `.pypirc` can be seen in the root of this repository + +```bash +pixi run -e publish publish-wheels --dist-directory /path/to/dist/ +``` + +You can also optionally pass in `--test` to publish to TestPyPI for validation before uploading to production, +`--repository-url` to specify a custom package index, or `--skip-existing` to skip already-uploaded wheels. + +
+ +--- ## Frequently Asked Questions ### What target platforms and architectures are supported? ITKPythonPackage currently supports building wheels for the following platforms and architectures: - - Windows 10 x86_64 platforms - - Windows 11 x86_64 platforms - - MacOS 15.0+ arm64 platforms - - Linux glibc 2.17+ (E.g. Ubuntu 18.04+) x86_64 platforms - - Linux glibc 2.28+ (E.g. Ubuntu 20.04+) aarch64 (ARMv8) platforms + +- Windows 10/11 x86_64 platforms +- macOS arm64 (Apple Silicon) +- macOS x86_64 (Intel) +- Linux glibc 2.17+ (e.g. Ubuntu 20.04+) x86_64 +- Linux glibc 2.28+ (e.g. Ubuntu 20.04+) aarch64 (ARMv8) Python 3.10+ is required. +[ITKRemoteModuleBuildTestPackageAction](https://github.com/InsightSoftwareConsortium/ITKRemoteModuleBuildTestPackageAction) +CI workflows support Python 3.10–3.11 on GitHub-hosted runners for: +- Ubuntu x86_64 +- Ubuntu aarch64 (ARM) +- macOS arm64 (Apple Silicon) +- Windows x86_64 + ### What should I do if my target platform/architecture does not appear on the list above? Please open an issue in the [ITKPythonPackage issue tracker](https://github.com/InsightSoftwareConsortium/ITKPythonPackage/issues) diff --git a/SuperbuildSupport/CMakeLists.txt b/SuperbuildSupport/CMakeLists.txt new file mode 100644 index 00000000..25311ae9 --- /dev/null +++ b/SuperbuildSupport/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.26.6 FATAL_ERROR) +# NOTE: 3.26.6 is the first cmake version to support Development.SABIModule + +project(ITKPythonPackageSuperbuild CXX) + +include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/ITKPythonPackage_Utils.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/ITKPythonPackage_SuperBuild.cmake) diff --git a/Utilities/Hooks/kw-commit-msg.py b/Utilities/Hooks/kw-commit-msg.py new file mode 100755 index 00000000..0d6b0af8 --- /dev/null +++ b/Utilities/Hooks/kw-commit-msg.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python3 +# ========================================================================== +# +# Copyright NumFOCUS +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0.txt +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ========================================================================== + +import os +import re +import subprocess +import sys + +from pathlib import Path + + +DEFAULT_LINE_LENGTH: int = 78 + + +def die(message, commit_msg_path): + print("commit-msg hook failure", file=sys.stderr) + print("-----------------------", file=sys.stderr) + print(message, file=sys.stderr) + print("-----------------------", file=sys.stderr) + print( + f""" +To continue editing, run the command + git commit -e -F "{commit_msg_path}" +(assuming your working directory is at the top).""", + file=sys.stderr, + ) + sys.exit(1) + + +def get_max_length(): + try: + result = subprocess.run( + ["git", "config", "--get", "hooks.commit-msg.ITKCommitSubjectMaxLength"], + capture_output=True, + text=True, + check=True, + ) + return int(result.stdout.strip()) + except (subprocess.CalledProcessError, ValueError): + return DEFAULT_LINE_LENGTH + + +def main(): + git_dir_path: Path = Path(os.environ.get("GIT_DIR", ".git")).resolve() + commit_msg_path: Path = git_dir_path / "COMMIT_MSG" + + if len(sys.argv) < 2: + die(f"Usage: {sys.argv[0]} ", commit_msg_path) + + input_file: Path = Path(sys.argv[1]) + if not input_file.exists(): + die( + f"Missing input_file {sys.argv[1]} for {sys.argv[0]} processing", + commit_msg_path, + ) + max_subjectline_length: int = get_max_length() + + original_input_file_lines: list[str] = [] + with open(input_file) as f_in: + original_input_file_lines = f_in.readlines() + + input_file_lines: list[str] = [] + for test_line in original_input_file_lines: + test_line = test_line.strip() + is_empty_line_before_subject: bool = ( + len(input_file_lines) == 0 and len(test_line) == 0 + ) + if test_line.startswith("#") or is_empty_line_before_subject: + continue + input_file_lines.append(f"{test_line}\n") + + with open(commit_msg_path, "w") as f_out: + f_out.writelines(input_file_lines) + + subject_line: str = input_file_lines[0] + + if len(subject_line) < 8: + die( + f"The first line must be at least 8 characters:\n--------\n{subject_line}\n--------", + commit_msg_path, + ) + if ( + len(subject_line) > max_subjectline_length + and not subject_line.startswith("Merge ") + and not subject_line.startswith("Revert ") + ): + die( + f"The first line may be at most {max_subjectline_length} characters:\n" + + "-" * max_subjectline_length + + f"\n{subject_line}\n" + + "-" * max_subjectline_length, + commit_msg_path, + ) + if re.match(r"^[ \t]|[ \t]$", subject_line): + die( + f"The first line may not have leading or trailing space:\n[{subject_line}]", + commit_msg_path, + ) + if not re.match( + r"^(Merge|Revert|BUG:|COMP:|DOC:|ENH:|PERF:|STYLE:|WIP:)\s", subject_line + ): + die( + f"""Start ITK commit messages with a standard prefix (and a space): + BUG: - fix for runtime crash or incorrect result + COMP: - compiler error or warning fix + DOC: - documentation change + ENH: - new functionality + PERF: - performance improvement + STYLE: - no logic impact (indentation, comments) + WIP: - Work In Progress not ready for merge +To reference GitHub issue XXXX, add "Issue #XXXX" to the commit message. +If the issue addresses an open issue, add "Closes #XXXX" to the message.""", + commit_msg_path, + ) + if re.match(r"^BUG: [0-9]+\.", subject_line): + die( + f'Do not put a "." after the bug number:\n\n {subject_line}', + commit_msg_path, + ) + del subject_line + + if len(input_file_lines) > 1: + second_line: str = input_file_lines[ + 1 + ].strip() # Remove whitespace at beginning and end + if len(second_line) == 0: + input_file_lines[1] = "\n" # Replace line with only newline + else: + die( + f'The second line of the commit message must be empty:\n"{second_line}" with length {len(second_line)}', + commit_msg_path, + ) + del second_line + + +if __name__ == "__main__": + main() diff --git a/Utilities/Hooks/prepare-commit-msg b/Utilities/Hooks/prepare-commit-msg new file mode 100755 index 00000000..276fd093 --- /dev/null +++ b/Utilities/Hooks/prepare-commit-msg @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +#========================================================================== +# +# Copyright NumFOCUS +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0.txt +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +#========================================================================== + +egrep-q() { + egrep "$@" >/dev/null 2>/dev/null +} + +# First argument is file containing commit message. +commit_msg="$1" + +# Check for our extra instructions. +egrep-q "^# Start ITK commit messages" -- "$commit_msg" && return 0 + +# Insert our extra instructions. +commit_msg_tmp="$commit_msg.$$" +instructions='#\ +# Start ITK commit messages with a standard prefix (and a space):\ +# BUG: - fix for runtime crash or incorrect result\ +# COMP: - compiler error or warning fix\ +# DOC: - documentation change\ +# ENH: - new functionality\ +# PERF: - performance improvement\ +# STYLE: - no logic impact (indentation, comments)\ +# WIP: - Work In Progress not ready for merge\ +#\ +# The first line of the commit message should preferably be 72 characters\ +# or less; the maximum allowed is 78 characters.\ +#\ +# Follow the first line commit summary with an empty line, then a detailed\ +# description in one or more paragraphs.\ +#' && +sed '/^# On branch.*$/ a\ +'"$instructions"' +/^# Not currently on any branch.*$/ a\ +'"$instructions"' +' "$commit_msg" > "$commit_msg_tmp" && +mv "$commit_msg_tmp" "$commit_msg" diff --git a/Utilities/scripts/build-all-latest-wheels.sh b/Utilities/scripts/build-all-latest-wheels.sh new file mode 100755 index 00000000..948c379e --- /dev/null +++ b/Utilities/scripts/build-all-latest-wheels.sh @@ -0,0 +1,121 @@ +#!/bin/bash +# Build ITK + all remote module Python wheels. +# Usage: ./scripts/build-all-latest-wheels.sh [options] +# --platform-env ENV Pixi environment (default: linux-py311) +# --itk-ref REF ITK branch, tag, or commit hash (default: main) +# --itk-repo URL ITK git URL +# --ipp-branch BRANCH ITKPythonPackage branch (default: python-build-system) +# --ipp-repo URL ITKPythonPackage git URL +# Example: +# ./scripts/build-all-latest-wheels.sh --itk-ref v6.0b02 --platform-env linux-py311 +set -euo pipefail + +# Defaults +PLATFORM_ENV="linux-py311" +ITK_REF="main" +ITK_REPO="https://github.com/InsightSoftwareConsortium/ITK.git" +IPP_REPO="https://github.com/BRAINSia/ITKPythonPackage.git" +IPP_BRANCH="python-build-system" + +while [[ $# -gt 0 ]]; do + case "$1" in + --platform-env) PLATFORM_ENV="$2"; shift 2 ;; + --itk-ref) ITK_REF="$2"; shift 2 ;; + --itk-repo) ITK_REPO="$2"; shift 2 ;; + --ipp-branch) IPP_BRANCH="$2"; shift 2 ;; + --ipp-repo) IPP_REPO="$2"; shift 2 ;; + *) echo "Unknown option: $1"; exit 1 ;; + esac +done + +TIMESTAMP=$(date +%Y%m%d%H%M%S) +WORKDIR="/tmp/${TIMESTAMP}_LatestITKPython" +DIST_DIR="${WORKDIR}/dist" + +mkdir -p "${DIST_DIR}" +echo "=== Build directory: ${WORKDIR}" +echo "=== Platform: ${PLATFORM_ENV}" +echo "=== ITK ref: ${ITK_REF}" + +# 1) Clone ITK +echo "=== Cloning ITK (${ITK_REF})..." +git clone "${ITK_REPO}" "${WORKDIR}/ITK" +git -C "${WORKDIR}/ITK" checkout "${ITK_REF}" + +# 2) Clone ITKPythonPackage +echo "=== Cloning ITKPythonPackage (${IPP_BRANCH})..." +git clone --branch "${IPP_BRANCH}" "${IPP_REPO}" "${WORKDIR}/ITKPythonPackage" + +# 3) Parse remote modules from ITK and clone each +echo "=== Cloning remote modules..." +MODULES_DIR="${WORKDIR}/modules" +mkdir -p "${MODULES_DIR}" +module_list=() + +for rc in "${WORKDIR}"/ITK/Modules/Remote/*.remote.cmake; do + name=$(basename "${rc}" .remote.cmake) + repo=$(grep 'GIT_REPOSITORY' "${rc}" | sed 's/.*GIT_REPOSITORY *//;s/ *)//;s/[[:space:]]*$//') + [ -z "${repo}" ] && continue + + echo " Cloning ${name} from ${repo}..." + if git clone --depth 1 "${repo}" "${MODULES_DIR}/${name}" 2>/dev/null; then + # Only keep modules that have Python wrapping + if [ -d "${MODULES_DIR}/${name}/wrapping" ] && [ -f "${MODULES_DIR}/${name}/pyproject.toml" ]; then + module_list+=("${name}") + else + rm -rf "${MODULES_DIR}/${name}" + fi + else + echo " WARNING: Failed to clone ${name}, skipping" + fi +done + +echo "=== ${#module_list[@]} modules with Python wrapping" + +# 4) Build ITK wheels +cd "${WORKDIR}/ITKPythonPackage" +echo "=== Building ITK Python wheels..." +pixi run -e "${PLATFORM_ENV}" -- python scripts/build_wheels.py \ + --platform-env "${PLATFORM_ENV}" \ + --itk-git-tag main \ + --itk-source-dir "${WORKDIR}/ITK" \ + --no-build-itk-tarball-cache \ + --no-use-sudo \ + --build-dir-root "${WORKDIR}/build" + +# Copy ITK wheels to dist +cp "${WORKDIR}"/build/dist/*.whl "${DIST_DIR}/" 2>/dev/null || true + +# 5) Build each remote module wheel +failed_modules=() +for name in "${module_list[@]}"; do + echo "=== Building ${name}..." + if pixi run -e "${PLATFORM_ENV}" -- python scripts/build_wheels.py \ + --platform-env "${PLATFORM_ENV}" \ + --itk-git-tag "${ITK_REF}" \ + --itk-source-dir "${WORKDIR}/ITK" \ + --module-source-dir "${MODULES_DIR}/${name}" \ + --no-build-itk-tarball-cache \ + --no-use-sudo \ + --skip-itk-build \ + --skip-itk-wheel-build \ + --build-dir-root "${WORKDIR}/build" 2>&1; then + cp "${MODULES_DIR}/${name}"/dist/*.whl "${DIST_DIR}/" 2>/dev/null || true + else + echo " FAILED: ${name}" + failed_modules+=("${name}") + fi +done + +# 6) Summary +echo "" +echo "=== Build complete ===" +echo "Wheels: ${DIST_DIR}" +ls -1 "${DIST_DIR}"/*.whl 2>/dev/null | wc -l +echo "total wheels produced" + +if [ ${#failed_modules[@]} -gt 0 ]; then + echo "" + echo "Failed modules (${#failed_modules[@]}):" + printf ' %s\n' "${failed_modules[@]}" +fi diff --git a/Utilities/scripts/build_all_latest_wheels.py b/Utilities/scripts/build_all_latest_wheels.py new file mode 100755 index 00000000..a75ee44c --- /dev/null +++ b/Utilities/scripts/build_all_latest_wheels.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python3 +"""Build ITK + all remote module Python wheels from latest main branches. + +Usage:: + + python scripts/build_all_latest_wheels.py [--platform-env linux-py311] + python scripts/build_all_latest_wheels.py --help +""" + +import argparse +import re +import shutil +import subprocess +import sys +from datetime import datetime +from pathlib import Path + + +def run(cmd: list[str], **kwargs) -> subprocess.CompletedProcess: + print(f" $ {' '.join(str(c) for c in cmd)}") + return subprocess.run(cmd, check=True, **kwargs) + + +def clone(repo: str, dest: Path, branch: str | None = None, depth: int | None = 1) -> bool: + cmd = ["git", "clone"] + if depth is not None: + cmd += ["--depth", str(depth)] + if branch: + cmd += ["--branch", branch] + cmd += [repo, str(dest)] + try: + run(cmd, capture_output=True) + return True + except subprocess.CalledProcessError: + return False + + +def parse_remote_modules(itk_dir: Path) -> list[tuple[str, str]]: + """Parse ITK remote .cmake files, return [(name, git_url), ...].""" + modules = [] + for rc in sorted((itk_dir / "Modules" / "Remote").glob("*.remote.cmake")): + name = rc.stem.replace(".remote", "") + text = rc.read_text() + m = re.search(r"GIT_REPOSITORY\s+(\S+)", text) + if m: + modules.append((name, m.group(1))) + return modules + + +def build_wheels( + ipp_dir: Path, + platform_env: str, + build_dir: Path, + itk_source: Path, + itk_ref: str = "main", + module_source: Path | None = None, + skip_itk: bool = False, +) -> bool: + cmd = [ + "pixi", + "run", + "-e", + platform_env, + "--", + "python", + "scripts/build_wheels.py", + "--platform-env", + platform_env, + "--itk-git-tag", + itk_ref, + "--itk-source-dir", + str(itk_source), + "--no-build-itk-tarball-cache", + "--no-use-sudo", + "--build-dir-root", + str(build_dir), + ] + if module_source: + cmd += ["--module-source-dir", str(module_source)] + if skip_itk: + cmd += ["--skip-itk-build", "--skip-itk-wheel-build"] + + try: + run(cmd, cwd=ipp_dir) + return True + except subprocess.CalledProcessError: + return False + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--platform-env", default="linux-py311", help="Pixi environment name" + ) + parser.add_argument( + "--ipp-branch", + default="python-build-system", + help="ITKPythonPackage branch to use", + ) + parser.add_argument( + "--ipp-repo", + default="https://github.com/BRAINSia/ITKPythonPackage.git", + help="ITKPythonPackage git URL", + ) + parser.add_argument( + "--itk-repo", + default="https://github.com/InsightSoftwareConsortium/ITK.git", + help="ITK git URL", + ) + parser.add_argument( + "--itk-ref", + default="main", + help="ITK branch, tag, or commit hash (default: main)", + ) + args = parser.parse_args() + + timestamp = datetime.now().strftime("%Y%m%d%H%M%S") + workdir = Path(f"/tmp/{timestamp}_LatestITKPython") + dist_dir = workdir / "dist" + dist_dir.mkdir(parents=True) + build_dir = workdir / "build" + + print(f"=== Build directory: {workdir}") + print(f"=== Platform: {args.platform_env}") + print(f"=== ITK ref: {args.itk_ref}") + + # 1) Clone ITK + print(f"=== Cloning ITK ({args.itk_ref})...") + itk_dir = workdir / "ITK" + clone(args.itk_repo, itk_dir, depth=None) + run(["git", "checkout", args.itk_ref], cwd=itk_dir) + + # 2) Clone ITKPythonPackage + print(f"=== Cloning ITKPythonPackage ({args.ipp_branch})...") + ipp_dir = workdir / "ITKPythonPackage" + clone(args.ipp_repo, ipp_dir, branch=args.ipp_branch) + + # 3) Clone remote modules + print("=== Cloning remote modules...") + modules_dir = workdir / "modules" + modules_dir.mkdir() + remote_modules = parse_remote_modules(itk_dir) + + module_list: list[str] = [] + for name, repo in remote_modules: + mod_dir = modules_dir / name + if not clone(repo, mod_dir): + print(f" WARNING: Failed to clone {name}, skipping") + continue + # Keep only modules with Python wrapping + if (mod_dir / "wrapping").is_dir() and (mod_dir / "pyproject.toml").is_file(): + module_list.append(name) + else: + shutil.rmtree(mod_dir) + + print(f"=== {len(module_list)} modules with Python wrapping") + + # 4) Build ITK wheels + print("=== Building ITK Python wheels...") + if not build_wheels(ipp_dir, args.platform_env, build_dir, itk_dir, args.itk_ref): + print("FATAL: ITK wheel build failed") + sys.exit(1) + + # Copy ITK wheels to dist + for whl in (build_dir / "dist").glob("*.whl"): + shutil.copy2(whl, dist_dir) + + # 5) Build each remote module wheel + failed: list[str] = [] + for name in module_list: + print(f"=== Building {name}...") + mod_dir = modules_dir / name + if build_wheels( + ipp_dir, + args.platform_env, + build_dir, + itk_dir, + args.itk_ref, + module_source=mod_dir, + skip_itk=True, + ): + for whl in (mod_dir / "dist").glob("*.whl"): + shutil.copy2(whl, dist_dir) + else: + print(f" FAILED: {name}") + failed.append(name) + + # 6) Summary + wheels = list(dist_dir.glob("*.whl")) + print() + print("=== Build complete ===") + print(f"Wheels: {dist_dir}") + print(f"{len(wheels)} total wheels produced") + + if failed: + print(f"\nFailed modules ({len(failed)}):") + for name in failed: + print(f" {name}") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/cmake/ITKPythonPackage.cmake b/cmake/ITKPythonPackage.cmake deleted file mode 100644 index 4190c4e4..00000000 --- a/cmake/ITKPythonPackage.cmake +++ /dev/null @@ -1,240 +0,0 @@ - -# ipp_ExternalProject_Add_Empty( ) -# -# Add an empty external project -# -function(ipp_ExternalProject_Add_Empty proj depends) - set(depends_args) - if(NOT depends STREQUAL "") - set(depends_args DEPENDS ${depends}) - endif() - ExternalProject_add(${proj} - SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj} - DOWNLOAD_COMMAND "" - UPDATE_COMMAND "" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - BUILD_IN_SOURCE 1 - BUILD_ALWAYS 1 - INSTALL_COMMAND "" - ${depends_args} - ) -endfunction() - -# ipp_get_module_dependees( ) -# -# Collect all modules depending on ````. -# -function(ipp_get_module_dependees itk-module output_var) - set(dependees "") - foreach(m_enabled IN LISTS ITK_MODULES_ENABLED) - list(FIND ITK_MODULE_${m_enabled}_DEPENDS ${itk-module} _index) - if(NOT _index EQUAL -1) - list(APPEND dependees ${m_enabled}) - endif() - endforeach() - list(REMOVE_DUPLICATES dependees) - set(${output_var} ${dependees} PARENT_SCOPE) -endfunction() - -function(_recursive_deps item-type item-category itk-item output_var) - set(_${itk-item}_deps ) - foreach(dep IN LISTS ITK_${item-type}_${itk-item}_${item-category}) - list(APPEND _${itk-item}_deps ${dep}) - _recursive_deps(${item-type} ${item-category} ${dep} _${itk-item}_deps) - endforeach() - list(APPEND ${output_var} ${_${itk-item}_deps}) - list(REMOVE_DUPLICATES ${output_var}) - set(${output_var} ${${output_var}} PARENT_SCOPE) -endfunction() - -# ipp_recursive_module_dependees( ) -# -# Recursively collect all modules depending on ````. -# -function(ipp_recursive_module_dependees itk-module output_var) - set(_${itk-module}_deps ) - _recursive_deps("MODULE" "DEPENDEES" ${itk-module} ${output_var}) - set(${output_var} ${${output_var}} PARENT_SCOPE) -endfunction() - -# ipp_is_module_leaf( ) -# -# If ```` has no dependencies, set `` to 1 -# otherwise set `` to 0. -# -function(ipp_is_module_leaf itk-module output_var) - set(leaf 1) - foreach(m_enabled IN LISTS ITK_MODULES_ENABLED) - list(FIND ITK_MODULE_${m_enabled}_DEPENDS ${itk-module} _index) - if(NOT _index EQUAL -1) - set(leaf 0) - break() - endif() - endforeach() - set(${output_var} ${leaf} PARENT_SCOPE) -endfunction() - -# ipp_is_module_python_wrapped( ) -# -# If ```` is wrapped in python, set `` to 1 -# otherwise set `` to 0. -# -function(ipp_is_module_python_wrapped itk-module output_var) - set(wrapped 0) - if(NOT DEFINED ITK_MODULE_${itk-module}_GROUP) - message(AUTHOR_WARNING "Variable ITK_MODULE_${itk-module}_GROUP is not defined") - else() - set(group ${ITK_MODULE_${itk-module}_GROUP}) - set(module_folder ${itk-module}) - # if any, strip ITK prefix - if(module_folder MATCHES "^ITK.+$") - string(REGEX REPLACE "^ITK(.+)$" "\\1" module_folder ${module_folder}) - endif() - if(EXISTS ${ITK_SOURCE_DIR}/Modules/${group}/${itk-module}/wrapping/CMakeLists.txt - OR EXISTS ${ITK_SOURCE_DIR}/Modules/${group}/${module_folder}/wrapping/CMakeLists.txt) - set(wrapped 1) - endif() - endif() - set(${output_var} ${wrapped} PARENT_SCOPE) -endfunction() - -# ipp_wheel_to_group( ) -# -# Extract ITK group name from wheel name (e.g 'itk-core' -> 'Core'). -# -# If the group name has less than 3 characters, take the uppercase -# value (e.g 'itk-io' -> 'IO'). -# -function(ipp_wheel_to_group wheel_name group_name_var) - string(REPLACE "itk-" "" _group ${wheel_name}) - string(SUBSTRING ${_group} 0 1 _first) - string(TOUPPER ${_first} _first_uc) - string(SUBSTRING ${_group} 1 -1 _remaining) - set(group_name "${_first_uc}${_remaining}") - # Convert to upper case if length <= 2 - string(LENGTH ${group_name} _length) - if(_length LESS 3) - string(TOUPPER ${group_name} group_name) - endif() - set(${group_name_var} ${group_name} PARENT_SCOPE) -endfunction() - -# ipp_pad_text( ) -# -# Example: -# -# set(row "Apple") -# ipp_pad_text(${row} 20 row) -# -# set(row "${row}Banana") -# ipp_pad_text(${row} 40 row) -# -# set(row "${row}Kiwi") -# ipp_pad_text(${row} 60 row) -# -# message(${row}) -# -# Output: -# -# Apple Banana Kiwi -# -function(ipp_pad_text text text_right_jusitfy_length output_var) - set(fill_char " ") - string(LENGTH "${text}" text_length) - math(EXPR pad_length "${text_right_jusitfy_length} - ${text_length} - 1") - if(pad_length GREATER 0) - string(RANDOM LENGTH ${pad_length} ALPHABET ${fill_char} text_dots) - set(${output_var} "${text} ${text_dots}" PARENT_SCOPE) - else() - set(${output_var} "${text}" PARENT_SCOPE) - endif() -endfunction() - -# ipp_display_table_row( ) -# -# Example: -# -# ipp_display_table_row("Apple^^Banana^^Kiwi" "20;20;20") -# ipp_display_table_row("Eiger^^Rainer^^Sajama" "20;20;20") -# -# Output: -# -# Apple Banana Kiwi -# Eiger Rainer Sajama -# -function(ipp_display_table_row values widths) - list(LENGTH values length) - set(text "") - math(EXPR range "${length} - 1") - foreach(index RANGE ${range}) - list(GET widths ${index} width) - list(GET values ${index} value) - string(REPLACE "^^" ";" value "${value}") - ipp_pad_text("${value}" ${width} value) - set(text "${text}${value}") - endforeach() - message(STATUS "${text}") -endfunction() - -# ipp_list_to_string( ) -# -# Example: -# -# set(values Foo Bar Oof) -# message("${values}") -# ipp_list_to_string("^^" "${values}" values) -# message("${values}") -# -# Output: -# -# Foo;Bar;Oof -# Foo^^Bar^^Oof -# -# Copied from Slicer/CMake/ListToString.cmake -# -function(ipp_list_to_string separator input_list output_string_var) - set(_string "") - # Get list length - list(LENGTH input_list list_length) - # If the list has 0 or 1 element, there is no need to loop over. - if(list_length LESS 2) - set(_string "${input_list}") - else() - math(EXPR last_element_index "${list_length} - 1") - foreach(index RANGE ${last_element_index}) - # Get current item_value - list(GET input_list ${index} item_value) - if(NOT item_value STREQUAL "") - # .. and append non-empty value to output string - set(_string "${_string}${item_value}") - # Append separator if current element is NOT the last one. - if(NOT index EQUAL last_element_index) - set(_string "${_string}${separator}") - endif() - endif() - endforeach() - endif() - set(${output_string_var} ${_string} PARENT_SCOPE) -endfunction() - -# No-op function allowing to shut-up "Manually-specified variables were not used by the project" -# warnings. -function(ipp_unused_vars) -endfunction() - -# -# Unused -# - -function(recursive_module_deps itk-module output_var) - set(_${itk-module}_deps ) - _recursive_deps("MODULE" "DEPENDS" ${itk-module} ${output_var}) - set(${output_var} ${${output_var}} PARENT_SCOPE) -endfunction() - -function(recursive_group_deps itk-group output_var) - set(_${itk-group}_deps ) - _recursive_deps("GROUP" "DEPENDS" ${itk-group} ${output_var}) - set(${output_var} ${${output_var}} PARENT_SCOPE) -endfunction() diff --git a/cmake/ITKPythonPackage_BuildWheels.cmake b/cmake/ITKPythonPackage_BuildWheels.cmake new file mode 100644 index 00000000..94fa89d9 --- /dev/null +++ b/cmake/ITKPythonPackage_BuildWheels.cmake @@ -0,0 +1,250 @@ +#----------------------------------------------------------------------------- +#------------------------------------------------------ +#---------------------------------- +# ITKPythonPackage_SUPERBUILD: OFF +#---------------------------------- +#------------------------------------------------------ +#----------------------------------------------------------------------------- +if(NOT DEFINED ITKPythonPackage_WHEEL_NAME) + message(FATAL_ERROR "ITKPythonPackage_WHEEL_NAME must be defined") +endif() + +message( + STATUS + "SuperBuild - ITKPythonPackage_WHEEL_NAME:${ITKPythonPackage_WHEEL_NAME}" +) + +set(components "PythonWheelRuntimeLibraries") + +message(STATUS "ITKPythonPackage_WHEEL_NAME: ${ITKPythonPackage_WHEEL_NAME}") + +# Extract ITK group name from wheel name +message(STATUS "") +set(msg "Extracting ITK_WHEEL_GROUP") +message(STATUS ${msg}) +ipp_wheel_to_group(${ITKPythonPackage_WHEEL_NAME} ITK_WHEEL_GROUP) +message(STATUS "${msg} - done [${ITK_WHEEL_GROUP}]") + +# +# Considering that +# +# * Every ITK module is associated with exactly one ITK group. +# * ITK module dependencies are specified independently of ITK groups +# +# we semi-arbitrarily defined a collection of wheels (see ``ITK_WHEEL_GROUPS``) +# that will roughly bundle the modules associated with each group. +# +# Based on the module dependency graph, the code below will determine which module +# should be packaged in which wheel. +# + +# List of ITK wheel groups +set(ITK_WHEEL_GROUPS "") +file(STRINGS "${CMAKE_SOURCE_DIR}/WHEEL_NAMES.txt" ITK_WHEELS REGEX "^itk-.+") +foreach(wheel_name IN LISTS ITK_WHEELS) + ipp_wheel_to_group(${wheel_name} group) + list(APPEND ITK_WHEEL_GROUPS ${group}) +endforeach() + +# Define below a reasonable dependency graph for ITK groups +set(ITK_GROUP_Core_DEPENDS) +set(ITK_GROUP_IO_DEPENDS Core) +set(ITK_GROUP_Numerics_DEPENDS Core) +set(ITK_GROUP_Filtering_DEPENDS Numerics) +set(ITK_GROUP_Segmentation_DEPENDS Filtering) +set(ITK_GROUP_Registration_DEPENDS Filtering) +set(ITK_GROUP_Video_DEPENDS Core) + +# ITK is needed to retrieve ITK module information +set(ITK_DIR ${ITK_BINARY_DIR}) +find_package(ITK REQUIRED) +set(CMAKE_MODULE_PATH ${ITK_CMAKE_DIR} ${CMAKE_MODULE_PATH}) + +# Sort wheel groups +include(TopologicalSort) +topological_sort(ITK_WHEEL_GROUPS ITK_GROUP_ _DEPENDS) + +# Set ``ITK_MODULE__DEPENDS`` variables +# +# Notes: +# +# * ``_DEPENDS`` variables are set after calling ``find_package(ITK REQUIRED)`` +# +# * This naming convention corresponds to what is used internally in ITK and allow +# to differentiate with variable like ``ITK_GROUP__DEPENDS`` set above. +# +foreach(module IN LISTS ITK_MODULES_ENABLED) + set(ITK_MODULE_${module}_DEPENDS "${${module}_DEPENDS}") +endforeach() + +# Set ``ITK_MODULE__DEPENDEES`` variables +foreach(module IN LISTS ITK_MODULES_ENABLED) + ipp_get_module_dependees(${module} ITK_MODULE_${module}_DEPENDEES) +endforeach() + +# Set ``ITK_GROUPS`` variable +file(GLOB group_dirs "${ITK_SOURCE_DIR}/Modules/*") +set(ITK_GROUPS) +foreach(dir IN LISTS group_dirs) + file(RELATIVE_PATH group "${ITK_SOURCE_DIR}/Modules" "${dir}") + if(NOT IS_DIRECTORY "${dir}" OR "${group}" MATCHES "^External$") + continue() + endif() + list(APPEND ITK_GROUPS ${group}) +endforeach() +message(STATUS "") +message(STATUS "ITK_GROUPS:${ITK_GROUPS}") + +# Set ``ITK_MODULE__GROUP`` variables +foreach(group IN LISTS ITK_GROUPS) + file( + GLOB_RECURSE _${group}_module_files + ${ITK_SOURCE_DIR}/Modules/${group}/itk-module.cmake + ) + foreach(_module_file ${_${group}_module_files}) + file(READ ${_module_file} _module_file_content) + string( + REGEX MATCH + "itk_module[ \n]*(\\([ \n]*)([A-Za-z0-9]*)" + _module_name + ${_module_file_content} + ) + set(_module_name ${CMAKE_MATCH_2}) + list(APPEND _${group}_module_list ${_module_name}) + set(ITK_MODULE_${_module_name}_GROUP ${group}) + endforeach() +endforeach() + +# Initialize ``ITK_WHEEL__MODULES`` variables that will contain list of modules +# to package in each wheel. +foreach(group IN LISTS ITK_WHEEL_GROUPS) + set(ITK_WHEEL_${group}_MODULES "") +endforeach() + +# Configure table display +set(row_widths + 40 + 20 + 20 + 10 + 90 + 12 +) +set(row_headers + MODULE_NAME + MODULE_GROUP + WHEEL_GROUP + IS_LEAF + MODULE_DEPENDEES_GROUPS + IS_WRAPPED +) +message(STATUS "") +ipp_display_table_row("${row_headers}" "${row_widths}") + +# Update ``ITK_WHEEL__MODULES`` variables +foreach(module IN LISTS ITK_MODULES_ENABLED) + ipp_is_module_leaf(${module} leaf) + set(dependees_groups) + if(NOT leaf) + set(dependees "") + ipp_recursive_module_dependees(${module} dependees) + foreach(dep IN LISTS dependees) + list(APPEND dependees_groups ${ITK_MODULE_${dep}_GROUP}) + endforeach() + if(dependees_groups) + list(REMOVE_DUPLICATES dependees_groups) + endif() + endif() + + # Filter out group not associated with a wheel + set(dependees_wheel_groups) + foreach(group IN LISTS dependees_groups) + list(FIND ITK_WHEEL_GROUPS ${group} _index) + if(_index EQUAL -1) + continue() + endif() + list(APPEND dependees_wheel_groups ${group}) + endforeach() + + set(wheel_group) + list(LENGTH dependees_wheel_groups _length) + + # Sanity check + if(leaf AND _length GREATER 0) + message(FATAL_ERROR "leaf module should not module depending on them !") + endif() + + if(_length EQUAL 0) + set(wheel_group "${ITK_MODULE_${module}_GROUP}") + elseif(_length EQUAL 1) + # Since packages depending on this module belong to one group, also package this module + set(wheel_group "${dependees_wheel_groups}") + elseif(_length GREATER 1) + # If more than one group is associated with the dependees, package the module in the + # "common ancestor" group. + set(common_ancestor_index 999999) + foreach(g IN LISTS dependees_wheel_groups) + list(FIND ITK_WHEEL_GROUPS ${g} _index) + if(NOT _index EQUAL -1 AND _index LESS common_ancestor_index) + set(common_ancestor_index ${_index}) + endif() + endforeach() + list(GET ITK_WHEEL_GROUPS ${common_ancestor_index} wheel_group) + endif() + + set(wheel_group_display ${wheel_group}) + + # XXX Hard-coded dispatch + if(module STREQUAL "ITKBridgeNumPy") + set(new_wheel_group "Core") + set(wheel_group_display "${new_wheel_group} (was ${wheel_group})") + set(wheel_group ${new_wheel_group}) + endif() + if(module STREQUAL "ITKVTK") + set(new_wheel_group "Core") + set(wheel_group_display "${new_wheel_group} (was ${wheel_group})") + set(wheel_group ${new_wheel_group}) + endif() + + # Associate module with a wheel + list(APPEND ITK_WHEEL_${wheel_group}_MODULES ${module}) + + # Display module info + ipp_is_module_python_wrapped(${module} is_wrapped) + ipp_list_to_string("^^" "${dependees_groups}" dependees_groups_str) + set(row_values + "${module};${ITK_MODULE_${module}_GROUP};${wheel_group_display};${leaf};${dependees_groups_str};${is_wrapped}" + ) + ipp_display_table_row("${row_values}" "${row_widths}") +endforeach() + +# Set list of components to install +set(components "") +foreach(module IN LISTS ITK_WHEEL_${ITK_WHEEL_GROUP}_MODULES) + list(APPEND components ${module}PythonWheelRuntimeLibraries) +endforeach() + +if(MSVC AND ITKPythonPackage_WHEEL_NAME STREQUAL "itk-core") + message(STATUS "Adding install rules for compiler runtime libraries") + # Put the runtime libraries next to the "itk/_*.pyd" C-extensions so they + # are found. + set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION "itk") + include(InstallRequiredSystemLibraries) +endif() + +#----------------------------------------------------------------------------- +# Install ITK components +message(STATUS "Adding install rules for components:") +foreach(component IN LISTS components) + message(STATUS " ${component}") + install( + CODE + " +unset(CMAKE_INSTALL_COMPONENT) +set(COMPONENT \"${component}\") +set(CMAKE_INSTALL_DO_STRIP 1) +include(\"${ITK_BINARY_DIR}/cmake_install.cmake\") +unset(CMAKE_INSTALL_COMPONENT) +" + ) +endforeach() diff --git a/cmake/ITKPythonPackage_SuperBuild.cmake b/cmake/ITKPythonPackage_SuperBuild.cmake new file mode 100644 index 00000000..1c59987b --- /dev/null +++ b/cmake/ITKPythonPackage_SuperBuild.cmake @@ -0,0 +1,368 @@ +#----------------------------------------------------------------------------- +#------------------------------------------------------ +#---------------------------------- +# ITKPythonPackage_SUPERBUILD: ON +#---------------------------------- +#------------------------------------------------------ +#----------------------------------------------------------------------------- + +option( + ITKPythonPackage_USE_TBB + "Build and use oneTBB in the ITK python package" + ON +) + +# Avoid "Manually-specified variables were not used by the project" warnings. +ipp_unused_vars(${PYTHON_VERSION_STRING} ${SKBUILD}) + +set(ep_download_extract_timestamp_arg) +if(CMAKE_VERSION VERSION_EQUAL "3.24" OR CMAKE_VERSION VERSION_GREATER "3.24") + # See https://cmake.org/cmake/help/latest/policy/CMP0135.html + set(ep_download_extract_timestamp_arg DOWNLOAD_EXTRACT_TIMESTAMP 1) +endif() + +#----------------------------------------------------------------------------- +# Options + +# When building different "flavor" of ITK python packages on a given platform, +# explicitly setting the following options allow to speed up package generation by +# re-using existing resources. +# +# ITK_SOURCE_DIR: Path to an existing source directory +# + +option(ITKPythonPackage_BUILD_PYTHON "Build ITK python module" ON) +mark_as_advanced(ITKPythonPackage_BUILD_PYTHON) + +set(ep_common_cmake_cache_args) +if(NOT CMAKE_CONFIGURATION_TYPES) + if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release") + endif() + list( + APPEND ep_common_cmake_cache_args + -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} + ) +endif() + +if(CMAKE_OSX_DEPLOYMENT_TARGET) + list( + APPEND ep_common_cmake_cache_args + -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${CMAKE_OSX_DEPLOYMENT_TARGET} + ) +endif() +if(CMAKE_OSX_ARCHITECTURES) + list( + APPEND ep_common_cmake_cache_args + -DCMAKE_OSX_ARCHITECTURES:STRING=${CMAKE_OSX_ARCHITECTURES} + ) +endif() + +if(CMAKE_MAKE_PROGRAM) + list( + APPEND ep_common_cmake_cache_args + -DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM} + ) +endif() + +if(CMAKE_CXX_COMPILER) + list( + APPEND ep_common_cmake_cache_args + -DCMAKE_CXX_COMPILER:PATH=${CMAKE_CXX_COMPILER} + ) +elseif(ENV{CXX}) + list(APPEND ep_common_cmake_cache_args -DCMAKE_CXX_COMPILER:PATH=$ENV{CXX}) +endif() + +if(CMAKE_C_COMPILER) + list( + APPEND ep_common_cmake_cache_args + -DCMAKE_C_COMPILER:PATH=${CMAKE_C_COMPILER} + ) +elseif(ENV{CC}) + list(APPEND ep_common_cmake_cache_args -DCMAKE_C_COMPILER:PATH=$ENV{CC}) +endif() + +#----------------------------------------------------------------------------- +# compile with multiple processors +include(ProcessorCount) +ProcessorCount(NPROC) +if(NOT NPROC EQUAL 0) + set(ENV{MAKEFLAGS} "-j${NPROC}") +endif() + +#----------------------------------------------------------------------------- +include(ExternalProject) + +#----------------------------------------------------------------------------- +# A separate project is used to download ITK, so that it can reused +# when building different "flavor" of ITK python packages + +message(STATUS "SuperBuild -") +message(STATUS "SuperBuild - ITK-source-download") + +if(NOT ITK_SOURCE_DIR AND ENV{ITK_SOURCE_DIR}) + set(ITK_SOURCE_DIR "$ENV{ITK_SOURCE_DIR}") +endif() + +set(tbb_depends "") +set(tbb_args -DModule_ITKTBB:BOOL=OFF) +if(ITKPythonPackage_USE_TBB) + set(TBB_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/../oneTBB-prefix") + set(TBB_DIR "${TBB_INSTALL_PREFIX}/lib/cmake/TBB") + set(tbb_args -DModule_ITKTBB:BOOL=ON -DTBB_DIR:PATH=${TBB_DIR}) + + set(tbb_cmake_cache_args) + if(CMAKE_OSX_DEPLOYMENT_TARGET) + list( + APPEND tbb_cmake_cache_args + -DCMAKE_CXX_OSX_DEPLOYMENT_TARGET_FLAG:STRING="-mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}" + -DCMAKE_C_OSX_DEPLOYMENT_TARGET_FLAG:STRING="-mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}" + ) + endif() + + ExternalProject_Add( + oneTBB + URL + https://github.com/oneapi-src/oneTBB/archive/refs/tags/v2022.2.0.tar.gz + URL_HASH + SHA256=f0f78001c8c8edb4bddc3d4c5ee7428d56ae313254158ad1eec49eced57f6a5b + CMAKE_ARGS + -DTBB_TEST:BOOL=OFF + -DCMAKE_INSTALL_PREFIX:PATH=${TBB_INSTALL_PREFIX} + -DCMAKE_INSTALL_LIBDIR:STRING=lib # Skip default initialization by GNUInstallDirs CMake module + ${ep_common_cmake_cache_args} ${tbb_cmake_cache_args} + ${ep_download_extract_timestamp_arg} + BUILD_BYPRODUCTS "${TBB_DIR}/TBBConfig.cmake" + USES_TERMINAL_DOWNLOAD 1 + USES_TERMINAL_UPDATE 1 + USES_TERMINAL_CONFIGURE 1 + USES_TERMINAL_BUILD 1 + ) + message(STATUS "SuperBuild - TBB: Enabled") + message(STATUS "SuperBuild - TBB_DIR: ${TBB_DIR}") + set(tbb_depends oneTBB) +endif() + +# Only add ITK-source-download ExternalProject if directory does not +# already exist +if(NOT EXISTS ${ITK_SOURCE_DIR}) + set(ITK_REPOSITORY "https://github.com/InsightSoftwareConsortium/ITK.git") + + if(NOT DEFINED ITK_GIT_TAG AND DEFINED ENV{ITK_GIT_TAG}) + set(ITK_GIT_TAG "$ENV{ITK_GIT_TAG}") + endif() + + if(NOT DEFINED ITK_GIT_TAG) + message( + FATAL_ERROR + "ITK_GIT_TAG must be defined when configuring cmake" + ) + endif() + ExternalProject_Add( + ITK-source-download + SOURCE_DIR ${ITK_SOURCE_DIR} + GIT_REPOSITORY ${ITK_REPOSITORY} + GIT_TAG ${ITK_GIT_TAG} + USES_TERMINAL_DOWNLOAD 1 + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + DEPENDS "${tbb_depends}" + ) + set(proj_status "") +else() + # Suppress unused variable warning + set(_unused "${ITK_GIT_TAG}") + ipp_externalproject_add_empty( + ITK-source-download + "" + ) + set(proj_status " (REUSE)") +endif() + +message(STATUS "SuperBuild - ITK_SOURCE_DIR: ${ITK_SOURCE_DIR}") +message(STATUS "SuperBuild - ITK-source-download[OK]${proj_status}") + +#----------------------------------------------------------------------------- +if(NOT ITKPythonPackage_BUILD_PYTHON) + return() +endif() + +#----------------------------------------------------------------------------- +# Search for python interpreter and libraries + +message(STATUS "SuperBuild -") +message(STATUS "SuperBuild - Searching for python") + +# Sanity checks +if(DEFINED Python3_INCLUDE_DIR AND NOT EXISTS ${Python3_INCLUDE_DIR}) + message( + FATAL_ERROR + "Python3_INCLUDE_DIR=${Python3_INCLUDE_DIR}: variable is defined but corresponds to nonexistent directory" + ) +endif() +if(DEFINED Python3_LIBRARY AND NOT EXISTS ${Python3_LIBRARY}) + message( + FATAL_ERROR + "Python3_LIBRARY=${Python3_LIBRARY}: variable is defined but corresponds to nonexistent file" + ) +endif() +if(DEFINED Python3_EXECUTABLE AND NOT EXISTS ${Python3_EXECUTABLE}) + message( + FATAL_ERROR + "Python3_EXECUTABLE=${Python3_EXECUTABLE}: variable is defined but corresponds to nonexistent file" + ) +endif() +if(DEFINED DOXYGEN_EXECUTABLE AND NOT EXISTS ${DOXYGEN_EXECUTABLE}) + message( + FATAL_ERROR + "DOXYGEN_EXECUTABLE=${DOXYGEN_EXECUTABLE}: variable is defined but corresponds to nonexistent file" + ) +endif() + +if( + NOT DEFINED Python3_INCLUDE_DIR + OR NOT DEFINED Python3_LIBRARY + OR NOT DEFINED Python3_EXECUTABLE +) + find_package(Python3 COMPONENTS Interpreter Development) + if(NOT Python3_EXECUTABLE AND _Python3_EXECUTABLE) + set(Python3_EXECUTABLE + ${_Python3_EXECUTABLE} + CACHE INTERNAL + "Path to the Python interpreter" + FORCE + ) + endif() +endif() +if(NOT DEFINED DOXYGEN_EXECUTABLE) + find_package(Doxygen REQUIRED) +endif() + +message(STATUS "SuperBuild - Python3_INCLUDE_DIR: ${Python3_INCLUDE_DIR}") +message(STATUS "SuperBuild - Python3_INCLUDE_DIRS: ${Python3_INCLUDE_DIRS}") +message(STATUS "SuperBuild - Python3_LIBRARY: ${Python3_LIBRARY}") +message(STATUS "SuperBuild - Python3_SABI_LIBRARY: ${Python3_SABI_LIBRARY}") +message(STATUS "SuperBuild - Python3_EXECUTABLE: ${Python3_EXECUTABLE}") +message(STATUS "SuperBuild - Searching for python[OK]") +message(STATUS "SuperBuild - DOXYGEN_EXECUTABLE: ${DOXYGEN_EXECUTABLE}") + +# CMake configuration variables to pass to ITK's build +set(ep_itk_cmake_cache_args "") +foreach(var BUILD_SHARED_LIBS ITK_BUILD_DEFAULT_MODULES) + if(DEFINED ${var}) + list(APPEND ep_itk_cmake_cache_args "-D${var}=${${var}}") + endif() +endforeach() +function(cached_variables RESULTVAR PATTERN) + get_cmake_property(variables CACHE_VARIABLES) + set(result) + foreach(variable ${variables}) + if(${variable} AND variable MATCHES "${PATTERN}") + list(APPEND result "-D${variable}=${${variable}}") + endif() + endforeach() + set(${RESULTVAR} ${result} PARENT_SCOPE) +endfunction() +cached_variables(itk_pattern_cached_vars "^(ITK_WRAP_)|(ITKGroup_)|(Module_)") +list(APPEND ep_itk_cmake_cache_args ${itk_pattern_cached_vars}) +# Todo, also pass all Module_* variables +message(STATUS "ITK CMake Cache Args - ${ep_itk_cmake_cache_args}") +#----------------------------------------------------------------------------- +# ITK: This project builds ITK and associated Python modules + +option( + ITKPythonPackage_ITK_BINARY_REUSE + "Reuse provided ITK_BINARY_DIR without configuring or building ITK" + OFF +) + +set(ITK_BINARY_DIR "${CMAKE_BINARY_DIR}/ITKb" CACHE PATH "ITK build directory") + +message(STATUS "SuperBuild -") +message(STATUS "SuperBuild - ITK => Requires ITK-source-download") +message(STATUS "SuperBuild - ITK_BINARY_DIR: ${ITK_BINARY_DIR}") + +if(NOT ITKPythonPackage_ITK_BINARY_REUSE) + set(_stamp "${CMAKE_BINARY_DIR}/ITK-prefix/src/ITK-stamp/ITK-configure") + if(EXISTS ${_stamp}) + execute_process(COMMAND ${CMAKE_COMMAND} -E remove ${_stamp}) + message(STATUS "SuperBuild - Force re-configure removing ${_stamp}") + endif() + + ExternalProject_Add( + ITK + DOWNLOAD_COMMAND "" + SOURCE_DIR ${ITK_SOURCE_DIR} + BINARY_DIR ${ITK_BINARY_DIR} + PREFIX "ITKp" + CMAKE_ARGS + -DBUILD_TESTING:BOOL=OFF + -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_INSTALL_PREFIX} + -DPY_SITE_PACKAGES_PATH:PATH=${CMAKE_INSTALL_PREFIX} + -DWRAP_ITK_INSTALL_COMPONENT_IDENTIFIER:STRING=PythonWheel + -DWRAP_ITK_INSTALL_COMPONENT_PER_MODULE:BOOL=ON + -DITK_LEGACY_SILENT:BOOL=ON -DITK_WRAP_PYTHON:BOOL=ON + -DDOXYGEN_EXECUTABLE:FILEPATH=${DOXYGEN_EXECUTABLE} + -DPython3_INCLUDE_DIR:PATH=${Python3_INCLUDE_DIR} + -DPython3_LIBRARY:FILEPATH=${Python3_LIBRARY} + -DPython3_SABI_LIBRARY:FILEPATH=${Python3_SABI_LIBRARY} + -DPython3_EXECUTABLE:FILEPATH=${Python3_EXECUTABLE} + ${ep_common_cmake_cache_args} ${tbb_args} ${ep_itk_cmake_cache_args} + ${ep_download_extract_timestamp_arg} + USES_TERMINAL_DOWNLOAD 1 + USES_TERMINAL_UPDATE 1 + USES_TERMINAL_CONFIGURE 1 + USES_TERMINAL_BUILD 1 + INSTALL_COMMAND "" + ) + set(proj_status "") +else() + # Sanity checks + if(NOT EXISTS "${ITK_BINARY_DIR}/CMakeCache.txt") + message( + FATAL_ERROR + "ITKPythonPackage_ITK_BINARY_REUSE is ON but ITK_BINARY_DIR variable is not associated with an ITK build directory. [ITK_BINARY_DIR:${ITK_BINARY_DIR}]" + ) + endif() + + ipp_externalproject_add_empty( + ITK + "" + ) + set(proj_status " (REUSE)") +endif() +ExternalProject_Add_StepDependencies(ITK download ITK-source-download) + +message(STATUS "SuperBuild - ITK[OK]${proj_status}") + +#----------------------------------------------------------------------------- +# ITKPythonPackage: This project adds install rules for the "RuntimeLibraries" +# components associated with the ITK project. + +message(STATUS "SuperBuild -") +message(STATUS "SuperBuild - ${PROJECT_NAME} => Requires ITK") + +ExternalProject_Add( + ${PROJECT_NAME} + SOURCE_DIR ${CMAKE_SOURCE_DIR} + BINARY_DIR ${CMAKE_BINARY_DIR}/${PROJECT_NAME}-build + DOWNLOAD_COMMAND "" + UPDATE_COMMAND "" + CMAKE_CACHE_ARGS + -DITKPythonPackage_SUPERBUILD:BOOL=0 + -DITK_BINARY_DIR:PATH=${ITK_BINARY_DIR} + -DITK_SOURCE_DIR:PATH=${ITK_SOURCE_DIR} + -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_INSTALL_PREFIX} + -DITKPythonPackage_WHEEL_NAME:STRING=${ITKPythonPackage_WHEEL_NAME} + -DITKPythonPackage_USE_TBB:BOOL=${ITKPythonPackage_USE_TBB} + ${ep_common_cmake_cache_args} + USES_TERMINAL_CONFIGURE 1 + INSTALL_COMMAND "" + DEPENDS ITK +) + +install(SCRIPT ${CMAKE_BINARY_DIR}/${PROJECT_NAME}-build/cmake_install.cmake) + +message(STATUS "SuperBuild - ${PROJECT_NAME}[OK]") diff --git a/cmake/ITKPythonPackage_Utils.cmake b/cmake/ITKPythonPackage_Utils.cmake new file mode 100644 index 00000000..5282b416 --- /dev/null +++ b/cmake/ITKPythonPackage_Utils.cmake @@ -0,0 +1,252 @@ +# ipp_ExternalProject_Add_Empty( ) +# +# Add an empty external project +# +function(ipp_ExternalProject_Add_Empty proj depends) + set(depends_args) + if(NOT depends STREQUAL "") + set(depends_args DEPENDS ${depends}) + endif() + ExternalProject_Add( + ${proj} + SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj} + DOWNLOAD_COMMAND "" + UPDATE_COMMAND "" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + BUILD_IN_SOURCE 1 + BUILD_ALWAYS 1 + INSTALL_COMMAND "" ${depends_args} + ) +endfunction() + +# ipp_get_module_dependees( ) +# +# Collect all modules depending on ````. +# +function(ipp_get_module_dependees itk-module output_var) + set(dependees "") + foreach(m_enabled IN LISTS ITK_MODULES_ENABLED) + list(FIND ITK_MODULE_${m_enabled}_DEPENDS ${itk-module} _index) + if(NOT _index EQUAL -1) + list(APPEND dependees ${m_enabled}) + endif() + endforeach() + list(REMOVE_DUPLICATES dependees) + set(${output_var} ${dependees} PARENT_SCOPE) +endfunction() + +function(_recursive_deps item-type item-category itk-item output_var) + set(_${itk-item}_deps) + foreach(dep IN LISTS ITK_${item-type}_${itk-item}_${item-category}) + list(APPEND _${itk-item}_deps ${dep}) + _recursive_deps(${item-type} ${item-category} ${dep} _${itk-item}_deps) + endforeach() + list(APPEND ${output_var} ${_${itk-item}_deps}) + list(REMOVE_DUPLICATES ${output_var}) + set(${output_var} ${${output_var}} PARENT_SCOPE) +endfunction() + +# ipp_recursive_module_dependees( ) +# +# Recursively collect all modules depending on ````. +# +function(ipp_recursive_module_dependees itk-module output_var) + set(_${itk-module}_deps) + _recursive_deps("MODULE" "DEPENDEES" ${itk-module} ${output_var}) + set(${output_var} ${${output_var}} PARENT_SCOPE) +endfunction() + +# ipp_is_module_leaf( ) +# +# If ```` has no dependencies, set `` to 1 +# otherwise set `` to 0. +# +function(ipp_is_module_leaf itk-module output_var) + set(leaf 1) + foreach(m_enabled IN LISTS ITK_MODULES_ENABLED) + list(FIND ITK_MODULE_${m_enabled}_DEPENDS ${itk-module} _index) + if(NOT _index EQUAL -1) + set(leaf 0) + break() + endif() + endforeach() + set(${output_var} ${leaf} PARENT_SCOPE) +endfunction() + +# ipp_is_module_python_wrapped( ) +# +# If ```` is wrapped in python, set `` to 1 +# otherwise set `` to 0. +# +function(ipp_is_module_python_wrapped itk-module output_var) + set(wrapped 0) + if(NOT DEFINED ITK_MODULE_${itk-module}_GROUP) + message( + AUTHOR_WARNING + "Variable ITK_MODULE_${itk-module}_GROUP is not defined" + ) + else() + set(group ${ITK_MODULE_${itk-module}_GROUP}) + set(module_folder ${itk-module}) + # if any, strip ITK prefix + if(module_folder MATCHES "^ITK.+$") + string( + REGEX REPLACE + "^ITK(.+)$" + "\\1" + module_folder + ${module_folder} + ) + endif() + if( + EXISTS + ${ITK_SOURCE_DIR}/Modules/${group}/${itk-module}/wrapping/CMakeLists.txt + OR EXISTS + ${ITK_SOURCE_DIR}/Modules/${group}/${module_folder}/wrapping/CMakeLists.txt + ) + set(wrapped 1) + endif() + endif() + set(${output_var} ${wrapped} PARENT_SCOPE) +endfunction() + +# ipp_wheel_to_group( ) +# +# Extract ITK group name from wheel name (e.g 'itk-core' -> 'Core'). +# +# If the group name has less than 3 characters, take the uppercase +# value (e.g 'itk-io' -> 'IO'). +# +function(ipp_wheel_to_group wheel_name group_name_var) + string(REPLACE "itk-" "" _group ${wheel_name}) + string(SUBSTRING ${_group} 0 1 _first) + string(TOUPPER ${_first} _first_uc) + string(SUBSTRING ${_group} 1 -1 _remaining) + set(group_name "${_first_uc}${_remaining}") + # Convert to upper case if length <= 2 + string(LENGTH ${group_name} _length) + if(_length LESS 3) + string(TOUPPER ${group_name} group_name) + endif() + set(${group_name_var} ${group_name} PARENT_SCOPE) +endfunction() + +# ipp_pad_text( ) +# +# Example: +# +# set(row "Apple") +# ipp_pad_text(${row} 20 row) +# +# set(row "${row}Banana") +# ipp_pad_text(${row} 40 row) +# +# set(row "${row}Kiwi") +# ipp_pad_text(${row} 60 row) +# +# message(${row}) +# +# Output: +# +# Apple Banana Kiwi +# +function(ipp_pad_text text text_right_jusitfy_length output_var) + set(fill_char " ") + string(LENGTH "${text}" text_length) + math(EXPR pad_length "${text_right_jusitfy_length} - ${text_length} - 1") + if(pad_length GREATER 0) + string(RANDOM LENGTH ${pad_length} ALPHABET ${fill_char} text_dots) + set(${output_var} "${text} ${text_dots}" PARENT_SCOPE) + else() + set(${output_var} "${text}" PARENT_SCOPE) + endif() +endfunction() + +# ipp_display_table_row( ) +# +# Example: +# +# ipp_display_table_row("Apple^^Banana^^Kiwi" "20;20;20") +# ipp_display_table_row("Eiger^^Rainer^^Sajama" "20;20;20") +# +# Output: +# +# Apple Banana Kiwi +# Eiger Rainer Sajama +# +function(ipp_display_table_row values widths) + list(LENGTH values length) + set(text "") + math(EXPR range "${length} - 1") + foreach(index RANGE ${range}) + list(GET widths ${index} width) + list(GET values ${index} value) + string(REPLACE "^^" ";" value "${value}") + ipp_pad_text("${value}" ${width} value) + set(text "${text}${value}") + endforeach() + message(STATUS "${text}") +endfunction() + +# ipp_list_to_string( ) +# +# Example: +# +# set(values Foo Bar Oof) +# message("${values}") +# ipp_list_to_string("^^" "${values}" values) +# message("${values}") +# +# Output: +# +# Foo;Bar;Oof +# Foo^^Bar^^Oof +# +# Copied from Slicer/CMake/ListToString.cmake +# +function(ipp_list_to_string separator input_list output_string_var) + set(_string "") + # Get list length + list(LENGTH input_list list_length) + # If the list has 0 or 1 element, there is no need to loop over. + if(list_length LESS 2) + set(_string "${input_list}") + else() + math(EXPR last_element_index "${list_length} - 1") + foreach(index RANGE ${last_element_index}) + # Get current item_value + list(GET input_list ${index} item_value) + if(NOT item_value STREQUAL "") + # .. and append non-empty value to output string + set(_string "${_string}${item_value}") + # Append separator if current element is NOT the last one. + if(NOT index EQUAL last_element_index) + set(_string "${_string}${separator}") + endif() + endif() + endforeach() + endif() + set(${output_string_var} ${_string} PARENT_SCOPE) +endfunction() + +# No-op function allowing to shut-up "Manually-specified variables were not used by the project" +# warnings. +function(ipp_unused_vars) +endfunction() + +# +# Unused +# + +function(recursive_module_deps itk-module output_var) + set(_${itk-module}_deps) + _recursive_deps("MODULE" "DEPENDS" ${itk-module} ${output_var}) + set(${output_var} ${${output_var}} PARENT_SCOPE) +endfunction() + +function(recursive_group_deps itk-group output_var) + set(_${itk-group}_deps) + _recursive_deps("GROUP" "DEPENDS" ${itk-group} ${output_var}) + set(${output_var} ${${output_var}} PARENT_SCOPE) +endfunction() diff --git a/conda-forge/README.md b/conda-forge/README.md new file mode 100644 index 00000000..140624c7 --- /dev/null +++ b/conda-forge/README.md @@ -0,0 +1,36 @@ +# conda-forge Submission + +This directory contains recipe files for submitting ITK packages to conda-forge +via [staged-recipes](https://github.com/conda-forge/staged-recipes). + +## Packages + +### libitk-wrapping + +A conda package containing ITK C++ libraries with full Python wrapping +artifacts (SWIG interfaces, CastXML outputs, compiled Python modules). +This package enables building ITK Python wheels and remote module wheels +without recompiling ITK from source. + +### Submission Process + +1. Fork [conda-forge/staged-recipes](https://github.com/conda-forge/staged-recipes) +2. Copy `libitk-wrapping/` into `recipes/libitk-wrapping/` +3. Open a PR against staged-recipes +4. Address conda-forge review feedback +5. Once merged, a feedstock will be created automatically + +### Updating the existing libitk feedstock + +The existing [libitk-feedstock](https://github.com/conda-forge/libitk-feedstock) +(currently at v5.4.5) should be updated to ITK 6 separately. The `libitk-wrapping` +package will depend on `libitk-devel` once both are at ITK 6. + +## Environment Variables for Custom Builds + +When building from a non-default ITK branch (e.g., for PR testing): + +```bash +export ITK_GIT_URL="https://github.com/BRAINSia/ITK.git" +export ITK_GIT_TAG="itk-conda-pythonpackage-support" +``` diff --git a/conda-forge/libitk-wrapping/bld.bat b/conda-forge/libitk-wrapping/bld.bat new file mode 100644 index 00000000..cce966e5 --- /dev/null +++ b/conda-forge/libitk-wrapping/bld.bat @@ -0,0 +1,60 @@ +@echo off +setlocal enabledelayedexpansion + +set BUILD_DIR=%SRC_DIR%\..\build +mkdir %BUILD_DIR% +cd %BUILD_DIR% + +cmake ^ + -G "Ninja" ^ + %CMAKE_ARGS% ^ + -D BUILD_SHARED_LIBS:BOOL=ON ^ + -D BUILD_TESTING:BOOL=OFF ^ + -D BUILD_EXAMPLES:BOOL=OFF ^ + -D CMAKE_BUILD_TYPE:STRING=Release ^ + -D "CMAKE_INSTALL_PREFIX=%LIBRARY_PREFIX%" ^ + ^ + -D ITK_WRAP_PYTHON:BOOL=ON ^ + -D ITK_WRAP_DOC:BOOL=ON ^ + -D ITK_LEGACY_SILENT:BOOL=ON ^ + -D CMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON ^ + ^ + -D ITK_WRAP_unsigned_short:BOOL=ON ^ + -D ITK_WRAP_double:BOOL=ON ^ + -D ITK_WRAP_complex_double:BOOL=ON ^ + -D "ITK_WRAP_IMAGE_DIMS:STRING=2;3;4" ^ + ^ + -D WRAP_ITK_INSTALL_COMPONENT_IDENTIFIER:STRING=PythonWheel ^ + -D WRAP_ITK_INSTALL_COMPONENT_PER_MODULE:BOOL=ON ^ + ^ + -D ITK_USE_SYSTEM_EXPAT:BOOL=ON ^ + -D ITK_USE_SYSTEM_HDF5:BOOL=ON ^ + -D ITK_USE_SYSTEM_JPEG:BOOL=ON ^ + -D ITK_USE_SYSTEM_PNG:BOOL=ON ^ + -D ITK_USE_SYSTEM_TIFF:BOOL=ON ^ + -D ITK_USE_SYSTEM_ZLIB:BOOL=ON ^ + -D ITK_USE_SYSTEM_FFTW:BOOL=ON ^ + -D ITK_USE_SYSTEM_EIGEN:BOOL=ON ^ + -D ITK_USE_FFTWD:BOOL=ON ^ + -D ITK_USE_FFTWF:BOOL=ON ^ + ^ + -D ITK_BUILD_DEFAULT_MODULES:BOOL=ON ^ + -D Module_ITKReview:BOOL=ON ^ + -D Module_ITKTBB:BOOL=ON ^ + -D Module_MGHIO:BOOL=ON ^ + -D Module_ITKIOTransformMINC:BOOL=ON ^ + -D Module_GenericLabelInterpolator:BOOL=ON ^ + -D Module_AdaptiveDenoising:BOOL=ON ^ + ^ + -D ITK_USE_KWSTYLE:BOOL=OFF ^ + -D "ITK_DEFAULT_THREADER:STRING=Pool" ^ + ^ + "%SRC_DIR%" + +if errorlevel 1 exit /b 1 + +cmake --build . --config Release +if errorlevel 1 exit /b 1 + +cmake --install . --config Release +if errorlevel 1 exit /b 1 diff --git a/conda-forge/libitk-wrapping/build.sh b/conda-forge/libitk-wrapping/build.sh new file mode 100755 index 00000000..48a9f657 --- /dev/null +++ b/conda-forge/libitk-wrapping/build.sh @@ -0,0 +1,86 @@ +#!/bin/bash +set -euo pipefail + +# Build ITK C++ with Python wrapping for conda-forge. +# Produces headers, shared libraries, CMake config, and all wrapping +# metadata (SWIG .i/.idx/.mdx, Python stubs) needed by downstream +# ITK remote modules. + +BUILD_DIR="${SRC_DIR}/../build" +mkdir -p "${BUILD_DIR}" +cd "${BUILD_DIR}" + +# TBB: enabled on Linux, disabled on macOS (conda TBB issues) +use_tbb=ON +if [ "$(uname)" = "Darwin" ]; then + use_tbb=OFF +fi + +# Cross-compilation support +if [[ "${CONDA_BUILD_CROSS_COMPILATION:-0}" == "1" ]]; then + try_run_results="${RECIPE_DIR}/TryRunResults-${target_platform}.cmake" + if [[ -f "${try_run_results}" ]]; then + CMAKE_ARGS="${CMAKE_ARGS} -C ${try_run_results}" + fi +fi + +cmake \ + -G "Ninja" \ + ${CMAKE_ARGS} \ + -D BUILD_SHARED_LIBS:BOOL=ON \ + -D BUILD_TESTING:BOOL=OFF \ + -D BUILD_EXAMPLES:BOOL=OFF \ + -D CMAKE_BUILD_TYPE:STRING=Release \ + -D "CMAKE_INSTALL_PREFIX=${PREFIX}" \ + \ + -D ITK_WRAP_PYTHON:BOOL=ON \ + -D ITK_WRAP_DOC:BOOL=ON \ + -D ITK_LEGACY_SILENT:BOOL=ON \ + -D CMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON \ + \ + -D ITK_WRAP_unsigned_short:BOOL=ON \ + -D ITK_WRAP_double:BOOL=ON \ + -D ITK_WRAP_complex_double:BOOL=ON \ + -D "ITK_WRAP_IMAGE_DIMS:STRING=2;3;4" \ + \ + -D WRAP_ITK_INSTALL_COMPONENT_IDENTIFIER:STRING=PythonWheel \ + -D WRAP_ITK_INSTALL_COMPONENT_PER_MODULE:BOOL=ON \ + \ + -D ITK_USE_SYSTEM_EXPAT:BOOL=ON \ + -D ITK_USE_SYSTEM_HDF5:BOOL=ON \ + -D ITK_USE_SYSTEM_JPEG:BOOL=ON \ + -D ITK_USE_SYSTEM_PNG:BOOL=ON \ + -D ITK_USE_SYSTEM_TIFF:BOOL=ON \ + -D ITK_USE_SYSTEM_ZLIB:BOOL=ON \ + -D ITK_USE_SYSTEM_FFTW:BOOL=ON \ + -D ITK_USE_SYSTEM_EIGEN:BOOL=ON \ + -D ITK_USE_FFTWD:BOOL=ON \ + -D ITK_USE_FFTWF:BOOL=ON \ + \ + -D ITK_BUILD_DEFAULT_MODULES:BOOL=ON \ + -D Module_ITKReview:BOOL=ON \ + -D Module_ITKTBB:BOOL=${use_tbb} \ + -D Module_MGHIO:BOOL=ON \ + -D Module_ITKIOTransformMINC:BOOL=ON \ + -D Module_GenericLabelInterpolator:BOOL=ON \ + -D Module_AdaptiveDenoising:BOOL=ON \ + \ + -D ITK_USE_KWSTYLE:BOOL=OFF \ + -D NIFTI_SYSTEM_MATH_LIB= \ + -D GDCM_USE_COREFOUNDATION_LIBRARY:BOOL=OFF \ + -D "ITK_DEFAULT_THREADER:STRING=Pool" \ + \ + -D "CMAKE_FIND_ROOT_PATH:PATH=${PREFIX}" \ + -D "CMAKE_FIND_ROOT_PATH_MODE_INCLUDE:STRING=ONLY" \ + -D "CMAKE_FIND_ROOT_PATH_MODE_LIBRARY:STRING=ONLY" \ + -D "CMAKE_FIND_ROOT_PATH_MODE_PROGRAM:STRING=NEVER" \ + -D "CMAKE_FIND_ROOT_PATH_MODE_PACKAGE:STRING=ONLY" \ + -D "CMAKE_FIND_FRAMEWORK:STRING=NEVER" \ + -D "CMAKE_FIND_APPBUNDLE:STRING=NEVER" \ + -D "CMAKE_PROGRAM_PATH=${BUILD_PREFIX}" \ + \ + "${SRC_DIR}" + +cmake --build . --config Release + +cmake --install . --config Release diff --git a/conda-forge/libitk-wrapping/meta.yaml b/conda-forge/libitk-wrapping/meta.yaml new file mode 100644 index 00000000..cbbd755f --- /dev/null +++ b/conda-forge/libitk-wrapping/meta.yaml @@ -0,0 +1,73 @@ +{% set version = "6.0.0" %} +{% set itk_tag = "v" + version %} + +package: + name: libitk-wrapping + version: {{ version }} + +source: + url: https://github.com/InsightSoftwareConsortium/ITK/archive/{{ itk_tag }}.tar.gz + # sha256: UPDATE_WITH_ACTUAL_HASH + +build: + number: 0 + skip: true # [win and vc<14] + +requirements: + build: + - cmake >=3.26 + - ninja + - {{ compiler('c') }} + - {{ stdlib("c") }} + - {{ compiler('cxx') }} + host: + - python + - swig >=4.1 + - castxml + - expat # [not win] + - hdf5 + - libjpeg-turbo + - libtiff + - libpng # [not win] + - eigen + - zlib # [not win] + - fftw + - tbb-devel + - doxygen + run: + - python + - tbb + - hdf5 + - fftw + - libjpeg-turbo + - libtiff + - libpng # [not win] + - expat # [not win] + - zlib # [not win] + +test: + commands: + # Verify CMake config is installed and discoverable + - test -d $PREFIX/lib/cmake/ITK* # [not win] + - if not exist %LIBRARY_LIB%\\cmake\\ITK* exit 1 # [win] + # Verify Python wrapping modules are installed + - test -f $PREFIX/lib/python*/site-packages/itk/__init__.py # [not win] + # Verify wrapping metadata is installed + - test -d $PREFIX/lib/cmake/ITK*/WrapITK/Typedefs # [not win] + +about: + home: https://itk.org + license: Apache-2.0 + license_file: + - LICENSE + - NOTICE + summary: > + ITK C++ libraries with Python wrapping artifacts for building + ITK Python wheels and remote module packages. + dev_url: https://github.com/InsightSoftwareConsortium/ITK + +extra: + recipe-maintainers: + - hjmjohnson + - thewtex + - blowekamp diff --git a/docs/Build_ITK_Module_Python_packages.rst b/docs/Build_ITK_Module_Python_packages.rst index dd88d7b9..2abdcfc8 100644 --- a/docs/Build_ITK_Module_Python_packages.rst +++ b/docs/Build_ITK_Module_Python_packages.rst @@ -1,238 +1,394 @@ ===================================== -Build ITK Module Python packages -====================================== - -ITK is organized into *modules*. Modules for ITK can be developed outside the -ITK source tree as *remote modules*. The *remote module* can be made -available in ITK's `CMake `_ configuration by -`contributing it -`_ -as a *remote module*. Python packages can also be generated for remote -modules and uploaded to the `Python Package Index (PyPI) `_ - -This section describes how to create, build, and upload ITK remote -module Python packages to PyPI. +Build ITK Module Python Packages +===================================== +ITK is organized into *modules*. Community members can extend ITK by developing +an ITK *external module* in a separate repository. When a module meets community +standards for documentation and maintenance it may be included in the ITK build +as a *remote module*. -.. include:: Prerequisites.rst +This section describes how to create, build, and publish Python packages for +ITK remote and external modules to PyPI. -Create the module -================= +Create a Module +=============== -To create an ITK module with Python wrapping, first run cookiecutter:: +To scaffold a new ITK module with Python wrapping, use the official template:: python -m pip install cookiecutter python -m cookiecutter gh:InsightSoftwareConsortium/ITKModuleTemplate # Fill in the information requested at the prompts +Fill in the prompts, then add your C++ filter classes. See +`Chapter 9 of the ITK Software Guide +`_ +for guidance on populating the module and writing ``.wrap`` files for SWIG. + -Then, add your classes. Reference documentation on `how to populate the module -`_ -can be found in the `ITK Software Guide -`_. +GitHub Actions Workflows +============================== +For most ITK external modules, the recommended and easiest path to building, testing, and +publishing Python wheels is the +`ITKRemoteModuleBuildTestPackageAction +`_ +reusable workflow. It handles fetching, configuring, and running +ITKPythonPackage build scripts automatically. -GitHub automated CI package builds -================================== +Every pull request and push triggers a build that: -Freely available GitHub Actions continous integration (CI) build and test -services for open source repositories are provided by -`GitHub `_. These services will build and test the C++ -code for your module and also generate Linux, macOS, and Windows Python -packages for your module. +- Compiles and runs your module's C++ tests +- Generates Linux, macOS, and Windows Python wheels -For every pull request and push to the GitHub repository, a GitHub Action will -run that builds and runs the repository's C++ tests and reports the results to -the `ITK CDash Dashboard `_. -Python packages are also generated for every commit. Packages for a commit's -build can be downloaded from the GitHub Action result page in the *Artifacts* -Section. +Wheel artifacts are downloadable from the **Artifacts** section of the +GitHub Actions run page. .. figure:: images/GitHubActionArtifacts.png - :alt: GitHub Action Artifacts + :alt: GitHub Action Artifacts -Reusable workflows available in -[ITKRemoteModuleBuildTestPackageAction](https://github.com/InsightSoftwareConsortium/ITKRemoteModuleBuildTestPackageAction) -can be used to handle the build-test-package process -for a majority of ITK external modules with minimal extra development. +To pin the specific ITKPythonPackage version used by the workflow (defaults are shown below): -Upload the packages to PyPI ----------------------------- +.. code-block:: yaml -First, `register for an account on PyPI `_. + uses: InsightSoftwareConsortium/ITKRemoteModuleBuildTestPackageAction/.github/workflows/build-test-package.yml@v5.4.5 + with: + itk-python-package-org: InsightSoftwareConsortium + itk-python-package-tag: main -Next, create a `~/.pypirc` file with your login credentials:: +.. include:: Prerequisites.rst - [distutils] - index-servers = - pypi - pypitest +Manual Builds +============= - [pypi] - username= - password= +For cases where the reusable workflow is not a good fit, the +download-and-build scripts can be run locally. Each script: - [pypitest] - repository=https://test.pypi.org/legacy/ - username= - password= +1. Downloads and installs the necessary build packages +2. Downloads the pre-built ITK binary tarball for the target platform from + `ITKPythonBuilds `_ +3. Extracts it to a local build directory +4. Builds your module wheels against the pre-built ITK -where `` and `` correspond to your PyPI account. +.. important:: + Place and run the script from your module's root directory. Or specify exact paths using the environment variables below -Then, upload wheels to the testing server. The wheels of dist/* are those that -you have built locally or have downloaded from a recent build listed at -`https://github.com/InsightSoftwareConsortium//actions`. -:: +Set the ITK PEP 440 compliant version before running any script:: - python -m pip install twine - python -m twine upload -r pypitest dist/* + export ITK_PACKAGE_VERSION=v6.0b01 # Linux / macOS + $env:ITK_PACKAGE_VERSION = "v6.0b01" # Windows PowerShell -Check out the packages on ``_ the testing server. +Linux (manylinux) +----------------- -Finally, upload the wheel packages to the production PyPI server:: +Requires Docker. Produces ``manylinux_2_28`` portable wheels. - python -m twine upload dist/* +.. code-block:: bash -Congratulations! Your packages can be installed with the commands:: + cd ~/ITKMyModule + # First build — downloads ITK cache, then builds module wheels + export MODULE_SRC_DIRECTORY=/path/to/module + bash ITKPythonPackage/scripts/dockcross-manylinux-download-cache-and-build-module-wheels.sh cp310 - python -m pip install --upgrade pip - python -m pip install itk- + # Subsequent builds — reuses the downloaded cache + bash ITKPythonPackage/scripts/dockcross-manylinux-build-module-wheels.sh cp310 -where `itk-` is the short name for your module that is -specified in the configured `pyproject.toml` file. +Omit the Python version argument to build all supported versions (cp310 and cp311): -Automate PyPI Package Uploads ------------------------------ +.. code-block:: bash -Automated uploads of Python packages to the Python package index, `PyPI -`_ will occur after adding a PyPI upload token to GitHub and -creating a Git tag. Create a PyPI API token by logging in to -``_. Generally, for the token name -use:: + export MODULE_SRC_DIRECTORY=/path/to/module + bash ITKPythonPackage/scripts/dockcross-manylinux-download-cache-and-build-module-wheels.sh - itk--github-action +macOS +----- -and for the scope use:: +.. code-block:: bash - itk- + cd ~/ITKMyModule + export MODULE_SRC_DIRECTORY=/path/to/module + bash ITKPythonPackage/scripts/macpython-download-cache-and-build-module-wheels.sh 3.10 3.11 -where `` is the short name for your module that is -specified in your configured `pyproject.toml` file. That scope will be available if you have -already uploaded a first set of wheels via twine as described above; and that -is the recommended approach. Otherwise, if you are creating the project at -this time, choose an unlimited scope, but be careful with the created token. +Windows +------- -.. figure:: images/PyPIToken.png - :alt: PyPI Token +Open a PowerShell terminal: + +.. code-block:: powershell + + cd C:\ITKMyModule + $env:ITK_PACKAGE_VERSION = "v6.0b01" + $env:MODULE_SRC_DIRECTORY = /path/to/module + .\ITKPythonPackage\scripts\windows-download-cache-and-build-module-wheels.ps1 -python_version_minor 10 + +Build multiple Python versions: + +.. code-block:: powershell + + foreach ($v in @(10, 11)) { + .\ITKPythonPackage\scripts\windows-download-cache-and-build-module-wheels.ps1 -python_version_minor $v + } + +.. important:: + Use a short build path (e.g. ``C:\BDR``) to avoid Windows 260-character + path length limits. See the Troubleshooting section in + :doc:`Build_ITK_Python_packages` for details. + +Key environment variables: + +.. list-table:: + :header-rows: 1 + :widths: 30 20 50 + + * - Variable + - Default + - Description + * - ``ITK_PACKAGE_VERSION`` + - ``v6.0b01`` + - PEP 440 ITK release to build against + * - ``TARGET_ARCH`` + - ``x64`` + - ``x64`` or ``aarch64`` + * - ``IMAGE_TAG`` + - ``20250913-6ea98ba`` + - Dockcross Docker image tag + * - ``MODULE_SRC_DIRECTORY`` + - script directory + - Path to your module source + * - ``MODULE_DEPS_DIR`` + - platform dependant + - Root directory for module dependency checkouts + * - ``DASHBOARD_BUILD_DIRECTORY`` + - platform dependant + - Root directory for build artifacts + * - ``MANYLINUX_VERSION`` + - ``_2_28`` + - Manylinux compatibility standard + * - ``CMAKE_OPTIONS`` + - *(empty)* + - Extra CMake ``-D`` definitions + * - ``ITKPYTHONPACKAGE_TAG`` + - ``main`` + - ITKPythonPackage branch/tag to fetch + * - ``ITKPYTHONPACKAGE_ORG`` + - ``InsightSoftwareConsortium`` + - ITKPythonPackage organization to fetch + * - ``NO_SUDO`` + - *(unset)* + - Set to skip ``sudo`` for Docker commands + * - ``DYLD_LIBRARY_PATH`` + - *(unset)* + - Extra library paths to bundle into wheels -Then, add the API token to the GitHub repository -`https://github.com/InsightSoftwareConsortium/`. Choose -the *Settings -> Secrets* page and add a key called *pypi_password*, setting -the password to be the token string that begins with `pypi-`. Note that this -will be a *token* instead of a password. Limit the scope of the token to the -individual package as a best practice. -.. figure:: images/GitHubPyPISecret.png - :alt: GitHub PyPI token secret +Use the Build Script Directly +==================================== -To push packages to PyPI, first, make sure to update the `version` for your -package in the *pyproject.toml* file. The initial version might be `0.1.0` or -`1.0.0`. Subsequent versions should follow -`semantic versioning `_. +For more control over build option, call ``build_wheels.py`` directly with +``--module-source-dir``. This approach will create a local ITK build by default: -Then, create a Git tag corresponding to the version. A Git tag can be created -in the GitHub user interface via *Releases -> Draft a new release*. +.. code-block:: bash -.. figure:: images/GitHubReleaseTag.png - :alt: GitHub Release Tag + pixi run python3 scripts/build_wheels.py \ + --platform-env macosx-py310 \ + --itk-git-tag v6.0b01 \ + --module-source-dir /path/to/ITKMyModule \ + --no-skip-itk-build \ + --no-skip-itk-wheel-build \ + --no-build-itk-tarball-cache -Automated platform scripts -========================== +.. _accelerated-builds: -Automated scripts are available in this repository to build Python packages -that are binary compatible with the Python distributions provided by -Python.org, Anaconda, and package managers like apt or Homebrew. -The following sections outline how to use the associated scripts for Linux, -macOS, and Windows. +Accelerated Builds with libitk-wrapping (pixi-build) +===================================================== -Once the builds are complete, Python packages will be available in the `dist` -directory. +When ITK is pre-installed in the conda/pixi environment via the +``libitk-wrapping`` package, the build system automatically skips the +expensive ITK C++ compilation (steps 01 and 02). This reduces remote +module build times from ~1-2 hours to ~15 minutes. -Linux ------ +To use this workflow, first build and install the ``libitk-wrapping`` +package: -To build portable Python packages on Linux, first `install Docker -`_. +.. code-block:: bash -For the first local build, clone the `ITKPythonPackage` repository inside your -and download the required ITK binary builds:: + cd packages/libitk-wrapping + pixi build - cd ~/ITKMyModule - git clone https://github.com/InsightSoftwareConsortium/ITKPythonPackage - ./ITKPythonPackage/scripts/dockcross-manylinux-download-cache-and-build-module-wheels.sh +Then build your module wheel — ITK will be detected automatically: -For subsequent builds, just call the build script:: +.. code-block:: bash - ./ITKPythonPackage/scripts/dockcross-manylinux-build-module-wheels.sh + pixi run -e linux-py311 python scripts/build_wheels.py \ + --platform-env linux-py311 \ + --module-source-dir /path/to/ITKMyModule \ + --skip-itk-build \ + --skip-itk-wheel-build \ + --no-build-itk-tarball-cache -macOS ------ +The detection checks ``CONDA_PREFIX`` and ``PIXI_ENVIRONMENT_DIR`` for +``lib/cmake/ITK-*/ITKConfig.cmake``. When found, the console will print:: -First, install the Python.org macOS Python distributions. This step requires sudo:: + Detected conda-installed ITK at (via $CONDA_PREFIX) + Using conda-installed ITK; skipping superbuild and C++ build steps. - cd ~/ITKMyModule - git clone https://github.com/InsightSoftwareConsortium/ITKPythonPackage - ./ITKPythonPackage/scripts/macpython-install-python.sh +To override the ITK source repository and tag for the ``libitk-wrapping`` +build (e.g., to test a feature branch): -Then, build the wheels:: +.. code-block:: bash - ./ITKPythonPackage/scripts/macpython-build-wheels.sh + export ITK_GIT_URL="https://github.com/MyOrg/ITK.git" + export ITK_GIT_TAG="my-feature-branch" + cd packages/libitk-wrapping + pixi build -Windows -------- -First, install Microsoft Visual Studio 2022, Git, and CMake, which should be added to the system PATH environmental variable. +Module Dependencies +=================== + +If your module depends on other ITK external modules, list them with +``--itk-module-deps`` (or the ``ITK_MODULE_PREQ`` environment variable for the +shell scripts): + +.. code-block:: bash + + pixi run python3 scripts/build_wheels.py \ + --platform-env macosx-py310 \ + --itk-git-tag v6.0b01 \ + --module-source-dir /path/to/ITKMyModule \ + --itk-module-deps "InsightSoftwareConsortium/ITKMeshToPolyData@v1.0.0" \ + --no-build-itk-tarball-cache + +For multiple dependencies, separate them with colons in **dependency order** +(each module listed before the modules that depend on it): + +.. code-block:: bash + + --itk-module-deps "org/ITKModA@v1.0:org/ITKModB@v2.1:org/ITKModC@main" + +The format for each entry is ``/@``. + +For the download-and-build shell scripts, set ``ITK_MODULE_PREQ`` instead: + +.. code-block:: bash + + export ITK_MODULE_PREQ="org/ITKModA@v1.0:org/ITKModB@v2.1" + bash ITKPythonPackage/scripts/dockcross-manylinux-download-cache-and-build-module-wheels.sh cp310 + +Dependencies are cloned to ``/`` before the +main module build begins. + + +Third-Party Libraries +===================== + +If your module links against a third-party library that is not part of ITK, +the wheel repair tools (``auditwheel``, ``delocate``, ``delvewheel``) need +to be able to find it to bundle it into the wheel. + +**Linux**: add the library's directory to ``LD_LIBRARY_PATH`` before running +the build script:: + + export LD_LIBRARY_PATH=/path/to/mylib/lib:$LD_LIBRARY_PATH + +**macOS**: add the directory to ``DYLD_LIBRARY_PATH``:: + + export DYLD_LIBRARY_PATH=/path/to/mylib/lib:$DYLD_LIBRARY_PATH + +**Windows**: pass the library directory via ``--lib-paths`` (or the +``-setup_options`` parameter of the PowerShell script): + +.. code-block:: powershell + + .\windows-download-cache-and-build-module-wheels.ps1 ` + -python_version_minor 10 ` + -setup_options "--exclude-libs nvcuda.dll" + + +Output +====== + +Finished wheels are placed in ``dist/`` inside your module directory +(or ``/dist/`` when running ``build_wheels.py`` directly). + +Example output:: + + dist/ + itk-mymodule-1.0.0-cp310-cp310-manylinux_2_28_x86_64.whl + itk-mymodule-1.0.0-cp310-cp310-macosx_13_0_arm64.whl + itk-mymodule-1.0.0-cp310-cp310-win_amd64.whl + + +Uploading to PyPI +================= + +Using the Publish Environment +----------------------------- + +ITKPythonPackage provides a ``publish`` Pixi environment with ``twine`` +pre-configured. Set your PyPI credentials (see ``.pypirc.example`` in the +repository root) and run: + +.. code-block:: bash + + export TWINE_USERNAME=__token__ + export TWINE_PASSWORD=pypi- + + # Test on TestPyPI first + pixi run -e publish publish-wheels \ + --dist-directory /path/to/module/dist \ + --test + + # Then upload to production PyPI + pixi run -e publish publish-wheels \ + --dist-directory /path/to/module/dist + +Pass ``--skip-existing`` to skip already-uploaded wheels when re-running after +a partial upload failure. + +Manual Upload +------------- + +Alternatively, install and use ``twine`` directly. + +Test on TestPyPI first:: + + pip install twine + twine upload -r testpypi dist/*.whl + +Then upload to production PyPI:: -Open a PowerShell terminal as Administrator, and install Python:: + twine upload dist/*.whl - PS C:\> Set-ExecutionPolicy Unrestricted - PS C:\> $pythonArch = "64" - PS C:\> iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/scikit-build/scikit-ci-addons/master/windows/install-python.ps1')) +Your package can then be installed with:: -In a PowerShell prompt, run the `windows-build-wheels.ps1` script:: + pip install itk- - PS C:\Windows> cd C:\ITKMyModule - PS C:\ITKMyModule> git clone https://github.com/InsightSoftwareConsortium/ITKPythonPackage.git IPP - PS C:\ITKMyModule> .\ITKPythonPackage\scripts\windows-download-cache-and-build-module-wheels.ps1 +Automated Upload via GitHub Actions +------------------------------------- -Other Notes ------------ +To automate publishing on every tagged release: -ITK modules sometimes depend on third-party libraries. To include third-party libraries -in development wheels for distribution, first add the library path to `LD_LIBRARY_PATH` -on Linux, `DYLD_LIBRARY_PATH` on MacOS, or `PATH` on Windows. Then, run the platform -build script. +1. Create a PyPI API token at ``_. + Name it ``itk--github-action`` and scope it to your + package (scope becomes available after the first manual upload). -ITK modules sometimes depend on other ITK modules. For instance, to build -[ITKBSplineGradient](https://github.com/InsightSoftwareConsortium/ITKBSplineGradient) -the user must first build ITK and then [ITKMeshToPolyData](https://github.com/InsightSoftwareConsortium/ITKmeshtopolydata). -ITKPythonPackage scripts support iterative prerequisite ITK module dependencies with the `ITK_MODULE_PREQ` -environment variable. + .. figure:: images/PyPIToken.png + :alt: PyPI Token -For Python build scripts, the ordered list of ITK module dependencies must be formatted as follows: +2. In your GitHub repository, go to **Settings → Secrets → Actions** and + add a secret named ``pypi_password`` with the token value (starts with + ``pypi-``). -``` -ITK_MODULE_PREQ=/@:/@:... -``` + .. figure:: images/GitHubPyPISecret.png + :alt: GitHub PyPI token secret -Where -- `module_org` is the name of a Github organization to use to fetch the module, i.e. "InsightSoftwareConsortium"; -- `module_name` is the name of the module, i.e. "ITKMeshToPolyData"; -- `module_tag` is the git tag or commit hash to use to fetch the module, i.e. "v1.0.0" +3. Create a GitHub Release (via **Releases → Draft a new release**). + The tag name should match the version in your ``pyproject.toml``. -Module names must be provided in order of dependencies for the build to succeed. + .. figure:: images/GitHubReleaseTag.png + :alt: GitHub Release Tag -For more information see the -[build scripts directory](https://github.com/InsightSoftwareConsortium/ITKPythonPackage/tree/master/scripts). +The ``ITKRemoteModuleBuildTestPackageAction`` workflow will detect the tag +and upload wheels automatically. diff --git a/docs/Build_ITK_Python_packages.rst b/docs/Build_ITK_Python_packages.rst index bb0d647c..781bc61d 100644 --- a/docs/Build_ITK_Python_packages.rst +++ b/docs/Build_ITK_Python_packages.rst @@ -1,14 +1,13 @@ -====================================== -Build ITK Python packages -====================================== +============================== +Build ITK Python Packages +============================== -This section describes how to builds ITK's Python packages. In most cases, the -:ref:`pre-built ITK binary wheels can be used `. - -ITK Python packages are built nightly on Kitware build systems and uploaded to -the `ITKPythonPackage GitHub releases page -`_. +This section describes how to build ITK's core Python wheels +(``itk-core``, ``itk-numerics``, ``itk-io``, ``itk-filtering``, +``itk-registration``, ``itk-segmentation``, and ``itk-meta``). In most cases, the pre-built ITK binary wheels can be used. +You may only need to build ITK from source if you need a custom patch, a specific unreleased +commit, or are developing ITK core itself. .. include:: Prerequisites.rst @@ -18,115 +17,469 @@ Automated platform scripts Steps required to build wheels on Linux, macOS and Windows have been automated. The following sections outline how to use the associated scripts. -Linux ------ -On any linux distribution with docker and bash installed, running the script dockcross-manylinux-build-wheels.sh will create 64-bit wheels for python 3.9+ in the dist directory. +Overview +======== -For example:: +The build is driven by ``scripts/build_wheels.py``, which orchestrates up to +seven sequential steps: - $ git clone https://github.com/InsightSoftwareConsortium/ITKPythonPackage.git - [...] +1. Build SuperBuild support components (oneTBB and other ITK dependencies) +2. Build ITK C++ with Python wrapping +3. Build Python wheels for each ITK subpackage +4. Fix up wheels if platform requires (``auditwheel`` / ``delocate`` / ``delvewheel``) +5. Import test +6. *(optional)* Build a remote module against the ITK build +7. *(optional)* Create a reusable ITK build tarball cache - $ ./scripts/dockcross-manylinux-build-wheels.sh - [...] +Step state is persisted to ``/dist/build_report-.json`` so that a +build interrupted part-way through can be resumed by re-running the same command. - $ ls -1 dist/ - itk-4.11.0.dev20170218-cp27-cp27m-manylinux2014_x86_64.whl - itk-4.11.0.dev20170218-cp27-cp27mu-manylinux2014_x86_64.whl - itk-4.11.0.dev20170218-cp34-cp34m-manylinux2014_x86_64.whl - itk-4.11.0.dev20170218-cp35-cp35m-manylinux2014_x86_64.whl - itk-4.11.0.dev20170218-cp36-cp36m-manylinux2014_x86_64.whl -macOS ------ +Setup +===== + +Clone the repository:: + + git clone https://github.com/InsightSoftwareConsortium/ITKPythonPackage.git + cd ITKPythonPackage + + +Platform Environments +===================== + +Each Pixi environment targets a specific OS and Python version. Pass the +environment name to ``--platform-env``: + +.. list-table:: + :header-rows: 1 + :widths: 30 70 + + * - ``--platform-env`` + - Notes + * - ``linux-py310`` + - Native Linux (GCC, glibc of host) + * - ``linux-py311`` + - Native Linux (GCC, glibc of host) + * - ``manylinux228-py310`` + - Portable Linux ≥ glibc 2.28 (x86_64 or aarch64 via Docker) + * - ``manylinux228-py311`` + - Portable Linux ≥ glibc 2.28 (x86_64 or aarch64 via Docker) + * - ``macosx-py310`` + - macOS (x86_64 and arm64) + * - ``macosx-py311`` + - macOS (x86_64 and arm64) + * - ``windows-py310`` + - Windows x86_64 (MSVC 2022) + * - ``windows-py311`` + - Windows x86_64 (MSVC 2022) + +If ``--platform-env`` is omitted, the platform is auto-detected from the +host OS and defaults to Python 3.10. + + +Building Wheels +=============== -First, install the Python.org macOS Python distributions. This step requires sudo:: +manylinux +--------- - ./scripts/macpython-install-python.sh +On any linux distribution with docker and bash installed, running the script dockcross-manylinux-build-wheels.sh will create 64-bit wheels for python 3.10+ in the dist directory. +.. code-block:: bash -Then, build the wheels:: + ./scripts/dockcross-manylinux-build-wheels.sh # py310 optionally specify python version - $ ./scripts/macpython-build-wheels.sh - [...] +Or you can build using a specific platform environment using: - $ ls -1 dist/ - itk-4.11.0.dev20170213-cp27-cp27m-macosx_10_6_x86_64.whl - itk-4.11.0.dev20170213-cp34-cp34m-macosx_10_6_x86_64.whl - itk-4.11.0.dev20170213-cp35-cp35m-macosx_10_6_x86_64.whl - itk-4.11.0.dev20170213-cp36-cp36m-macosx_10_6_x86_64.whl +Linux +----- + +.. code-block:: bash + + pixi run python3 scripts/build_wheels.py \ + --platform-env linux-py310 \ + --itk-git-tag v6.0b01 \ + --no-build-itk-tarball-cache + +macOS +----- + +.. code-block:: bash + + pixi run python3 scripts/build_wheels.py \ + --platform-env macosx-py310 \ + --itk-git-tag v6.0b01 \ + --no-build-itk-tarball-cache Windows ------- -First, install Microsoft Visual Studio 2015, Git, and CMake, which should be added to the system PATH environmental variable. - -Open a PowerShell terminal as Administrator, and install Python:: - - PS C:\> Set-ExecutionPolicy Unrestricted - PS C:\> $pythonArch = "64" - PS C:\> iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/scikit-build/scikit-ci-addons/master/windows/install-python.ps1')) - -In a PowerShell prompt:: - - PS C:\Windows> cd C:\ - PS C:\> git clone https://github.com/InsightSoftwareConsortium/ITKPythonPackage.git IPP - PS C:\> cd IPP - PS C:\IPP> .\scripts\windows-build-wheels.ps1 - [...] - - PS C:\IPP> ls dist - Directory: C:\IPP\dist - - - Mode LastWriteTime Length Name - ---- ------------- ------ ---- - -a---- 4/9/2017 11:14 PM 63274441 itk-4.11.0.dev20170407-cp35-cp35m-win_amd64.whl - -a---- 4/10/2017 2:08 AM 63257220 itk-4.11.0.dev20170407-cp36-cp36m-win_amd64.whl - -We need to work in a short directory to avoid path length limitations on -Windows, so the repository is cloned into C:\IPP. - -Also, it is very important to disable antivirus checking on the C:\IPP -directory. Otherwise, the build system conflicts with the antivirus when many -files are created and deleted quickly, which can result in Access Denied -errors. Windows 10 ships with an antivirus application, Windows Defender, that -is enabled by default. - -.. The below instructions are outdated and need to be re-written -.. sdist -.. ----- -.. -.. To create source distributions, sdist's, that will be used by pip to compile a wheel for installation if a binary wheel is not available for the current Python version or platform:: -.. -.. $ python setup.py sdist --formats=gztar,zip -.. [...] -.. -.. $ ls -1 dist/ -.. itk-4.11.0.dev20170216.tar.gz -.. itk-4.11.0.dev20170216.zip -.. -.. Manual builds -.. ============= -.. -.. Building ITK Python wheels -.. -------------------------- -.. -.. Build the ITK Python wheel with the following command:: -.. -.. python3 -m venv build-itk -.. ./build-itk/bin/pip install --upgrade pip -.. ./build-itk/bin/pip install -r requirements-dev.txt numpy -.. ./build-itk/bin/python setup.py bdist_wheel -.. -.. Build a wheel for a custom version of ITK -.. ----------------------------------------- -.. -.. To build a wheel for a custom version of ITK, point to your ITK git repository -.. with the `ITK_SOURCE_DIR` CMake variable:: -.. -.. ./build-itk/bin/python setup.py bdist_wheel -- \ -.. -DITK_SOURCE_DIR:PATH=/path/to/ITKPythonPackage-core-build/ITK -.. -.. Other CMake variables can also be passed with `-D` after the double dash. +Similarly, on windows + +.. code-block:: powershell + + pixi run python3 scripts/build_wheels.py ` + --platform-env windows-py310 ` + --itk-git-tag v6.0b01 ` + --no-build-itk-tarball-cache + + +Finished wheels are placed in ``/dist/``. + +.. note:: + Building ITK from source takes 1–2 hours on typical hardware. Pass + ``--build-itk-tarball-cache`` to save the result as a reusable tarball + and avoid rebuilding on subsequent runs. + +.. tip:: + For even faster builds, install the ``libitk-wrapping`` conda package + (see ``packages/libitk-wrapping/``). When present in the pixi/conda + environment, the build system automatically detects it and skips the + ITK C++ compilation entirely. See + :ref:`Build ITK Module Python Packages ` for details. + + +Key Options +=========== + +.. list-table:: + :header-rows: 1 + :widths: 35 15 50 + + * - Option + - Default + - Description + * - ``--platform-env`` + - auto-detected + - Target platform and Python version (see table above) + * - ``--itk-git-tag`` + - ``main`` + - ITK version, branch, or commit to build + * - ``--itk-package-version`` + - auto (git describe) + - PEP 440 version string embedded in the wheels + * - ``--build-dir-root`` + - ``../ITKPythonPackage-build`` + - Root directory for all build artifacts + * - ``--manylinux-version`` + - ``_2_28`` + - Manylinux compatibility standard (e.g. ``_2_28``, ``_2_34``) + * - ``--itk-source-dir`` + - cloned automatically + - Path to a local ITK checkout (skips git clone) + * - ``--module-source-dir`` + - *(none)* + - Path to an ITK external module to build against the ITK build + * - ``--itk-module-deps`` + - *(none)* + - Colon-delimited prerequisite modules (``org/repo@tag:org/repo@tag``) + * - ``--build-itk-tarball-cache`` + - off + - Package the ITK build as a reusable ``.tar.zst`` / ``.zip`` + * - ``--no-build-itk-tarball-cache`` + - *(default)* + - Skip tarball generation + * - ``--skip-itk-build`` / ``--no-skip-itk-build`` + - off + - Skip step 2 (ITK C++ build) when a build already exists + * - ``--skip-itk-wheel-build`` / ``--no-skip-itk-wheel-build`` + - off + - Skip step 3 (wheel build) when wheels already exist + * - ``--cleanup`` + - off + - Remove intermediate build files after completion + * - ``--use-ccache`` + - off + - Enable ccache to speed up recompilation + * - ``--macosx-deployment-target`` + - ``10.7`` + - Minimum macOS version for compiled binaries + * - ``--use-sudo`` / ``--no-use-sudo`` + - off + - Pass ``sudo`` to Docker commands (manylinux only) + +Any remaining positional arguments are forwarded to CMake as ``-D`` definitions, +for example:: + + pixi run python3 scripts/build_wheels.py \ + --platform-env macosx-py310 \ + --itk-git-tag v6.0b01 \ + -DBUILD_SHARED_LIBS:BOOL=OFF + + +Environment Variable Equivalents +--------------------------------- + +All ``--`` options can alternatively be set as environment variables, which is +useful in CI pipelines: + +.. list-table:: + :header-rows: 1 + :widths: 35 65 + + * - Environment Variable + - Equivalent Option + * - ``ITK_GIT_TAG`` + - ``--itk-git-tag`` + * - ``ITK_PACKAGE_VERSION`` + - ``--itk-package-version`` + * - ``ITK_SOURCE_DIR`` + - ``--itk-source-dir`` + * - ``MANYLINUX_VERSION`` + - ``--manylinux-version`` + * - ``TARGET_ARCH`` + - target architecture (``x64`` or ``aarch64``) + * - ``IMAGE_TAG`` + - Docker image tag for manylinux builds + * - ``NO_SUDO`` + - ``--no-use-sudo`` + * - ``USE_CCACHE`` + - ``--use-ccache`` + * - ``CMAKE_OPTIONS`` + - extra CMake ``-D`` definitions + * - ``MACOSX_DEPLOYMENT_TARGET`` + - ``--macosx-deployment-target`` + + +Building from a Local ITK Source +================================= + +If you have a local ITK checkout with custom patches or an unreleased fix, pass +``--itk-source-dir`` to use it instead of cloning from GitHub: + +.. code-block:: bash + + pixi run python3 scripts/build_wheels.py \ + --platform-env macosx-py310 \ + --itk-source-dir /path/to/your/ITK \ + --itk-git-tag my-bugfix-branch \ + --no-build-itk-tarball-cache + +For manylinux, use the shell wrapper which handles Docker volume mounting: + +.. code-block:: bash + + ITK_SOURCE_DIR=/path/to/your/ITK \ + bash scripts/dockcross-manylinux-build-wheels.sh cp310 + + +Building ITK Tarball Caches +============================ + +Tarball caches package the entire ITK build output (headers, libraries, wrapper +artifacts) so that external module builds can skip the costly ITK compilation step. +These are the same caches distributed via `ITKPythonBuilds +`_ releases. + +By default these scripts build for python version 3.10 and 3.11 but you can optionally add a specific version to build for + +Linux / macOS: + +.. code-block:: bash + + ITK_GIT_TAG=v6.0b01 + bash scripts/make_tarballs.sh py310 + +Windows (PowerShell): + +.. code-block:: powershell + + $env:ITK_GIT_TAG = "v6.0b01" + .\scripts\make_windows_zip.ps1 py310 + +Or via ``build_wheels.py`` directly: + +.. code-block:: bash + + pixi run python3 scripts/build_wheels.py \ + --platform-env macosx-py310 \ + --itk-git-tag v6.0b01 \ + --build-itk-tarball-cache + +.. important:: + Build caches embed absolute paths. They must be extracted to the same path + they were built from or CMake will fail to locate required files. The + standard CI/CD paths are: + + - **manylinux (Docker)**: ``/work/ITKPythonPackage-build`` + - **macOS**: ``/Users/svc-dashboard/D/P/ITKPythonPackage-build`` + - **Windows**: ``C:\BDR`` + + The ``make_tarballs.sh`` and ``make_windows_zip.ps1`` scripts enforce these + paths automatically. + + +Output Artifacts +================ + +.. list-table:: + :header-rows: 1 + :widths: 30 70 + + * - Artifact + - Location + * - Built wheels + - ``/dist/*.whl`` + * - Effective command line + - ``/effective_cmdline_.sh`` + * - manylinux tarball caches + - ``/ITKPythonBuilds-manylinux_2_28-*.tar.zst`` + * - Linux tarball caches + - ``/ITKPythonBuilds-linux-*.tar.zst`` + * - macOS tarball caches + - ``/ITKPythonBuilds-macosx-*.tar.zst`` + * - Windows ZIP cache + - ``/ITKPythonBuilds-windows.zip`` + +Example wheel names:: + + itk-6.0.0-cp310-cp310-manylinux_2_28_x86_64.whl + itk-6.0.0-cp310-cp310-macosx_13_0_arm64.whl + itk-6.0.0-cp310-cp310-win_amd64.whl + + +Testing Built Wheels +==================== + +Install and smoke-test a wheel directly from the ``dist/`` directory: + +.. code-block:: bash + + pip install dist/itk-6.0.0-cp310-cp310-macosx_13_0_arm64.whl + python -c "import itk; print(itk.__version__)" + + +Publishing +========== + +ITKPythonPackage provides a lightweight ``publish`` Pixi environment with +`twine `_ for uploading wheels to PyPI and the +`GitHub CLI `_ for uploading tarball caches to GitHub +Releases. Install it with:: + + pixi install -e publish + + +Publishing Wheels to PyPI +------------------------- + +The ``publish-wheels`` task validates wheel metadata with ``twine check`` and +then uploads all ``.whl`` files from a ``dist/`` directory. + +**Authentication** — set environment variables or configure ``~/.pypirc`` +(see ``.pypirc.example`` in the repository root): + +.. code-block:: bash + + export TWINE_USERNAME=__token__ + export TWINE_PASSWORD=pypi- + +Upload to **TestPyPI** first for validation: + +.. code-block:: bash + + pixi run -e publish publish-wheels \ + --dist-directory /path/to/dist \ + --test + +Then upload to **production PyPI**: + +.. code-block:: bash + + pixi run -e publish publish-wheels \ + --dist-directory /path/to/dist + +Additional options: + +.. list-table:: + :header-rows: 1 + :widths: 30 70 + + * - Option + - Description + * - ``--test`` + - Upload to TestPyPI (``https://test.pypi.org/legacy/``) + * - ``--repository-url`` + - Custom package index URL (overrides ``--test``) + * - ``--skip-existing`` + - Skip already-uploaded wheels instead of failing + + +Publishing Tarball Caches to GitHub Releases +-------------------------------------------- + +The ``publish-tarball-cache`` task uploads ``.tar.zst`` (POSIX) and ``.zip`` +(Windows) build caches to a GitHub Release on the +`ITKPythonBuilds `_ +repository. + +**Authentication** — set the ``GH_TOKEN`` environment variable or run +``gh auth login`` beforehand. + +.. code-block:: bash + + pixi run -e publish publish-tarball-cache \ + --itk-package-version v6.0b02 \ + --build-dir-root /path/to/build \ + --create-release + +Additional options: + +.. list-table:: + :header-rows: 1 + :widths: 30 70 + + * - Option + - Description + * - ``--itk-package-version`` + - **(required)** Release tag name (e.g. ``v6.0b02``) + * - ``--build-dir-root`` + - Root of the build directory; tarballs are found in its parent + (POSIX ``.tar.zst``) or inside it (Windows ``.zip``) + * - ``--repo`` + - Target GitHub repository (default: ``InsightSoftwareConsortium/ITKPythonBuilds``) + * - ``--create-release`` + - Create the GitHub Release if it does not already exist + +.. note:: + The ``--clobber`` flag is used internally so re-uploading a tarball for the + same platform replaces the existing asset without manual cleanup. + + +Troubleshooting +=============== + +Path Length Issues (Windows) +----------------------------- + +If you encounter path length errors: + +Windows has a 260-character path limit by default. Use a short build directory +(e.g. ``C:\BDR``) and optionally enable long path support: + +.. code-block:: powershell + + New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" ` + -Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force + +Antivirus Conflicts (Windows) +------------------------------ + +The build creates and deletes large numbers of files rapidly, which can trigger +Windows Defender and produce "Access Denied" errors. Add the build directory to +Windows Defender exclusions: + +1. Open **Windows Security → Virus & threat protection → Manage settings** +2. Scroll to **Exclusions → Add or remove exclusions** +3. Add the build root (e.g. ``C:\BDR``) + +Docker Permissions (Linux) +--------------------------- + +If Docker requires ``sudo``, pass ``--use-sudo`` to ``build_wheels.py`` or set +``NO_SUDO=`` (empty string) before running the manylinux shell script. To add +your user to the ``docker`` group instead:: + + sudo usermod -aG docker $USER + # Then log out and back in diff --git a/docs/Miscellaneous.rst b/docs/Miscellaneous.rst index d7ae223f..acf64221 100644 --- a/docs/Miscellaneous.rst +++ b/docs/Miscellaneous.rst @@ -2,7 +2,7 @@ Miscellaneous ============= -Written by Jean-Christophe Fillion-Robin and Matt McCormick from Kitware Inc. +Written by Jean-Christophe Fillion-Robin and Matt McCormick from Kitware Inc and Cavan Riley from the University of Iowa. It is covered by the Apache License, Version 2.0: diff --git a/docs/Prerequisites.rst b/docs/Prerequisites.rst index 83b0f1a7..73b22012 100644 --- a/docs/Prerequisites.rst +++ b/docs/Prerequisites.rst @@ -1,9 +1,52 @@ Prerequisites ============= -Building wheels requires: +The following tools are required to build ITK Python wheels locally. -- CMake -- Git -- C++ Compiler - Platform specific requirements are summarized in scikit-build documentation. -- Python +All Platforms +------------- + +`Pixi `_ is the primary build environment manager. It automatically +provisions the correct Python version, compiler toolchain, CMake, Ninja, and all +other build dependencies for each target platform. Manual installation of compilers +or CMake is not required when using Pixi. + +Install Pixi: + +.. code-block:: bash + + # Linux or macOS + curl -fsSL https://pixi.sh/install.sh | bash + + # Windows (PowerShell) + powershell -ExecutionPolicy Bypass -c "irm -useb https://pixi.sh/install.ps1 | iex" + +You will also need `Git `_ 2.x or later. + +Linux +----- + +Portable manylinux builds require Docker (or an OCI-compatible runtime such as +Podman or nerdctl) to run the manylinux container environment. + +Install Docker by following the official `Docker Engine installation guide +`_. + +macOS +----- + +No additional tools are required beyond Pixi. The Pixi ``macosx-build`` +environment provides the Clang 1.10.0 compiler toolchain and the +`delocate `_ wheel repair utility. + +Windows +------- + +`Microsoft Visual Studio 2022 `_ +(or the Build Tools for Visual Studio 2022) with the +**Desktop development with C++** workload is required. + +.. note:: + Pixi environments provision Python, CMake, Ninja, and build helpers + (``auditwheel`` on Linux, ``delocate`` on macOS, ``delvewheel`` on Windows) + automatically. Only Docker (Linux) and MSVC (Windows) require separate installation. diff --git a/docs/Quick_start_guide.rst b/docs/Quick_start_guide.rst deleted file mode 100644 index f1ae8205..00000000 --- a/docs/Quick_start_guide.rst +++ /dev/null @@ -1,247 +0,0 @@ -=========================== -Quick start guide -=========================== - -.. _quick-start: - -Installation ------------- - -To install the ITK Python package:: - - $ pip install itk - - -Usage ------ - -Basic example -.............. - -Here is a simple python script that reads an image, applies a median image filter (radius of 2 pixels), and writes the resulting image in a file. - -.. literalinclude:: code/ReadMedianWrite.py - -ITK and NumPy -............. - -A common use case for using ITK in Python is to mingle NumPy and ITK operations on raster data. ITK provides a large number of I/O image formats and several sophisticated image processing algorithms not available in any other packages. The ability to intersperse that with the SciPy ecosystem provides a great tool for rapid prototyping. - -The following script shows how to integrate NumPy and `itk.Image`: - -.. literalinclude:: code/MixingITKAndNumPy.py - :lines: 16-59 - -NumPy and `itk.Mesh`: - -.. literalinclude:: code/MixingITKAndNumPy.py - :lines: 62-76 - -NumPy and `itk.Transform`: - -.. literalinclude:: code/MixingITKAndNumPy.py - :lines: 96-115 - -NumPy and `itk.Matrix`, VNL vectors, and VNL matrices: - -.. literalinclude:: code/MixingITKAndNumPy.py - :lines: 118- - -ITK and Xarray -.............. - -An `itk.Image` can be converted to and from an `xarray.DataArray -`_ while -preserving metadata:: - - da = itk.xarray_from_image(image) - - image = itk.image_from_xarray(da) - -ITK and VTK -............ - -An `itk.Image` can be converted to and from a `vtk.vtkImageData -`_ while -preserving metadata:: - - vtk_image = itk.vtk_image_from_image(image) - - image = itk.image_from_vtk_image(vtk_image) - -ITK and napari -.............. - -An `itk.Image` can be converted to and from a `napari.layers.Image -`_ while -preserving metadata with the `itk-napari-conversion package -`_. - -ITK Python types -................ - -+---------------------+--------------------+--------------------+ -| C++ type | Python type | NumPy dtype | -+=====================+====================+====================+ -| float | itk.F | np.float32 | -+---------------------+--------------------+--------------------+ -| double | itk.D | np.float64 | -+---------------------+--------------------+--------------------+ -| unsigned char | itk.UC | np.uint8 | -+---------------------+--------------------+--------------------+ -| std::complex | itk.complex[itk.F] | np.complex64 | -+---------------------+--------------------+--------------------+ - -This list is not exhaustive and is only presented to illustrate the type names. The complete list of types can be found in the `ITK Software Guide `_. - -Types can also be obtained from their name in the C programming language: - -.. literalinclude:: code/CompareITKTypes.py - :lines: 5 - -To cast the pixel type of an image, use `.astype`: - -.. literalinclude:: code/Cast.py - :lines: 10-18 - -Metadata dictionary -................... - -An `itk.Image` has a metadata dict of `key: value` pairs. - - -The metadata dictionary can be retrieved with:: - - meta_dict = dict(image) - -For example:: - - In [3]: dict(image) - Out[3]: - {'0008|0005': 'ISO IR 100', - '0008|0008': 'ORIGINAL\\PRIMARY\\AXIAL', - '0008|0016': '1.2.840.10008.5.1.4.1.1.2', - '0008|0018': '1.3.12.2.1107.5.8.99.484849.834848.79844848.2001082217554549', - '0008|0020': '20010822', - -Individual dictionary items can be accessed or assigned:: - - print(image['0008|0008']) - - image['origin'] = [4.0, 2.0, 2.0] - -In the Python dictionary interface to image metadata, keys for the spatial -metadata, the *'origin'*, *'spacing'*, and *'direction'*, are reversed in -order from `image.GetOrigin()`, `image.GetSpacing()`, `image.GetDirection()` -to be consistent with the `NumPy array index order -`_ -resulting from pixel buffer array views on the image. - -Access pixel data with NumPy indexing -..................................... - -Array views of an `itk.Image` provide a way to set and get pixel values with NumPy indexing syntax, e.g.:: - - In [6]: image[0,:2,4] = [5,5] - - In [7]: image[0,:4,4:6] - Out[7]: - NDArrayITKBase([[ 5, -997], - [ 5, -1003], - [ -993, -999], - [ -996, -994]], dtype=int16) - -Input/Output (IO) -................. - -Convenient functions are provided read and write from ITK's many supported -file formats:: - - image = itk.imread('image.tif') - - # Read in with a specific pixel type. - image = itk.imread('image.tif', itk.F) - - # Read in an image series. - # Pass a sorted list of files. - image = itk.imread(['image1.png', 'image2.png', 'image3.png']) - - # Read in a volume from a DICOM series. - # Pass a directory. - # Only a single series, sorted spatially, will be returned. - image = itk.imread('/a/dicom/directory/') - - # Write an image. - itk.imwrite(image, 'image.tif') - - - # Read a mesh. - mesh = itk.meshread('mesh.vtk') - - # Write a mesh. - itk.meshwrite(mesh, 'mesh.vtk') - - - # Read a spatial transform. - transform = itk.transformread('transform.h5') - - # Write a spatial transform. - itk.transformwrite(transform, 'transform.h5') - -Image filters and Image-like inputs and outputs -............................................... - -All `itk` functional image filters operate on an `itk.Image` but also: - -- `xarray.DataArray `_ * -- `numpy.ndarray `_ -- `dask.array.Array `_ - -\* Preserves image metadata - -Filter parameters -................. - -ITK filter parameters can be specified in the following ways: - -.. literalinclude:: code/FilterParameters.py - :lines: 10- - -Filter types -............ - -In `itk`, filters are optimized at compile time for each image pixel type and -image dimension. There are two ways to instantiate these filters with the `itk` -Python wrapping: - -- *Implicit (recommended)*: Type information is automatically detected from the data. Typed filter objects and images are implicitly created. - -.. literalinclude:: code/ImplicitInstantiation.py - :lines: 8- - -- *Explicit*: This can be useful if an appropriate type cannot be determined implicitly or when a different filter type than the default is desired. - -To specify the type of the filter, use the `ttype` keyword argument. Explicit instantiation of a median image filter: - -.. literalinclude:: code/ExplicitInstantiation.py - :lines: 8- - -Instantiate an ITK object -......................... - -There are two types of ITK objects. Most ITK objects, such as images, filters, or adapters, are instantiated the following way: - -.. literalinclude:: code/InstantiateITKObjects.py - :lines: 6-8 - -Some objects, like a Matrix, Vector, or RGBPixel, do not require the attribute `.New()` to be added to instantiate them: - -.. literalinclude:: code/InstantiateITKObjects.py - :lines: 11 - -In case of doubt, look at the attributes of the object you are trying to instantiate. - -Examples --------- - -Examples can be found in the `ITKSphinxExamples project `_. diff --git a/docs/_static/custom.css b/docs/_static/custom.css new file mode 100644 index 00000000..7b5c8b9d --- /dev/null +++ b/docs/_static/custom.css @@ -0,0 +1,29 @@ +/* -- ITKPythonPackage custom styles (pydata-sphinx-theme) -- */ + +/* Sidebar brand text */ +.navbar-brand p { + font-weight: 700; + font-size: 1.15rem; +} + +/* Better code block styling */ +.highlight pre { + border-radius: 6px; + font-size: 0.85rem; +} + +/* Admonition tweaks */ +.admonition { + border-radius: 6px; + font-size: 0.92rem; +} + +/* Quick-links card grid on index */ +.sd-card { + border-radius: 8px; + transition: box-shadow 0.2s ease; +} + +.sd-card:hover { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12); +} diff --git a/docs/conf.py b/docs/conf.py index b642ec55..8be81c96 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,28 +1,5 @@ import os -# -*- coding: utf-8 -*- -# -# ITKPythonPackage documentation build configuration file, created by -# sphinx-quickstart on Mon May 29 15:53:20 2017. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) - - # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. @@ -32,8 +9,10 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [] - +extensions = [ + "sphinx_copybutton", + "sphinx_design", +] # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] @@ -51,21 +30,10 @@ copyright = "2017, Jean-Christophe Fillion-Robin and Matt McCormick" author = "Jean-Christophe Fillion-Robin and Matt McCormick" -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = "" -# The full version, including alpha/beta/rc tags. -release = "" +version = os.environ.get("READTHEDOCS_VERSION", "") +release = version -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None +language = "en" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -81,21 +49,27 @@ # -- Options for HTML output ---------------------------------------------- -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = "default" - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -# html_theme_options = {} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". +html_theme = "furo" html_static_path = ["_static"] +html_css_files = ["custom.css"] +html_title = "ITKPythonPackage" + +html_theme_options = { + "source_repository": "https://github.com/InsightSoftwareConsortium/ITKPythonPackage", + "source_branch": "main", + "source_directory": "docs/", + "sidebar_hide_name": False, + "navigation_with_keys": True, + "top_of_page_buttons": ["view", "edit"], + "light_css_variables": { + "color-brand-primary": "#2962FF", + "color-brand-content": "#2962FF", + }, + "dark_css_variables": { + "color-brand-primary": "#82B1FF", + "color-brand-content": "#82B1FF", + }, +} # -- Options for HTMLHelp output ------------------------------------------ @@ -156,19 +130,7 @@ "ITKPythonPackage Documentation", author, "ITKPythonPackage", - "One line description of project.", + "Scripts and configuration for building ITK Python binary wheels.", "Miscellaneous", ), ] - - -# -- Read The Docs ----------------------------------------------------- - -# on_rtd is whether we are on readthedocs.io -on_rtd = os.environ.get("READTHEDOCS", None) == "True" - -if not on_rtd: # only import and set the theme if we're building docs locally - import sphinx_rtd_theme - - html_theme = "sphinx_rtd_theme" - html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] diff --git a/docs/index.rst b/docs/index.rst index 32fc2fbc..00db0e9f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,36 +1,62 @@ -Welcome to ITKPythonPackage's documentation! -============================================ +ITKPythonPackage +================ -This project provides a script to generate `pyproject.toml` files used to build -ITK Python wheels and infrastructure to build ITK external module Python +Build infrastructure for ITK Python wheels and ITK external module Python wheels. `ITK `_ is an open-source, cross-platform system that provides developers with an extensive suite of software tools for image analysis. -To install the pre-built stable ITK Python package:: +.. code-block:: bash - $ pip install itk + pip install itk For more information on ITK's Python wrapping, see `an introduction in the Book 1, Chapter 3 of the ITK Software Guide `_. There are also many `downloadable examples documented in Sphinx `_. +---- -.. toctree:: - :maxdepth: 2 - :caption: Contents +Quick Links +----------- + +.. grid:: 2 + :gutter: 3 + + .. grid-item-card:: Prerequisites + :link: Prerequisites + :link-type: doc + + Platform requirements and tooling setup for building ITK wheels. + + .. grid-item-card:: Build ITK Python Packages + :link: Build_ITK_Python_packages + :link-type: doc + + Build core ITK wheels (``itk-core``, ``itk-numerics``, ``itk-io``, etc.) + from source. - Quick_start_guide.rst - Build_ITK_Module_Python_packages.rst - Build_ITK_Python_packages.rst - Miscellaneous.rst + .. grid-item-card:: Build ITK Module Packages + :link: Build_ITK_Module_Python_packages + :link-type: doc -Indices and tables -================== + Create, build, and publish Python packages for ITK remote and external + modules. + + .. grid-item-card:: Miscellaneous + :link: Miscellaneous + :link-type: doc + + License, authors, and additional resources. + +---- + +.. toctree:: + :maxdepth: 3 -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` + Prerequisites + Build_ITK_Python_packages + Build_ITK_Module_Python_packages + Miscellaneous diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index 82133027..7d464dc3 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,2 +1,4 @@ sphinx -sphinx_rtd_theme +furo +sphinx-copybutton +sphinx-design diff --git a/itkVersion.py b/itkVersion.py deleted file mode 100644 index acf9bffb..00000000 --- a/itkVersion.py +++ /dev/null @@ -1,31 +0,0 @@ -from packaging.version import Version - -# Version needs to be python PEP 440 compliant (no leading v) -VERSION = '6.0b2'.removeprefix("v") - -def get_versions(): - """Returns versions for the ITK Python package. - - from itkVersion import get_versions - - # Returns the ITK repository version - get_versions()['version'] - - # Returns the package version. Since GitHub Releases do not support the '+' - # character in file names, this does not contain the local version - # identifier in nightly builds, i.e. - # - # '4.11.0.dev20170208' - # - # instead of - # - # '4.11.0.dev20170208+139.g922f2d9' - get_versions()['package-version'] - """ - - Version(VERSION) # Raise InvalidVersion exception if not PEP 440 compliant - - versions = {} - versions['version'] = VERSION - versions['package-version'] = VERSION.split('+')[0] - return versions diff --git a/packages/libitk-wrapping/build-libitk-wrapping.bat b/packages/libitk-wrapping/build-libitk-wrapping.bat new file mode 100644 index 00000000..781af091 --- /dev/null +++ b/packages/libitk-wrapping/build-libitk-wrapping.bat @@ -0,0 +1,62 @@ +@echo off +setlocal enabledelayedexpansion + +:: Build ITK C++ with Python wrapping for use as a conda package (Windows). + +set BUILD_DIR=%SRC_DIR%\..\build +mkdir %BUILD_DIR% +cd %BUILD_DIR% + +cmake ^ + -G "Ninja" ^ + %CMAKE_ARGS% ^ + -D BUILD_SHARED_LIBS:BOOL=ON ^ + -D BUILD_TESTING:BOOL=OFF ^ + -D BUILD_EXAMPLES:BOOL=OFF ^ + -D CMAKE_BUILD_TYPE:STRING=Release ^ + -D "CMAKE_INSTALL_PREFIX=%LIBRARY_PREFIX%" ^ + ^ + -D ITK_WRAP_PYTHON:BOOL=ON ^ + -D ITK_WRAP_DOC:BOOL=ON ^ + -D ITK_LEGACY_SILENT:BOOL=ON ^ + -D CMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON ^ + ^ + -D ITK_WRAP_unsigned_short:BOOL=ON ^ + -D ITK_WRAP_double:BOOL=ON ^ + -D ITK_WRAP_complex_double:BOOL=ON ^ + -D "ITK_WRAP_IMAGE_DIMS:STRING=2;3;4" ^ + ^ + -D WRAP_ITK_INSTALL_COMPONENT_IDENTIFIER:STRING=PythonWheel ^ + -D WRAP_ITK_INSTALL_COMPONENT_PER_MODULE:BOOL=ON ^ + ^ + -D ITK_USE_SYSTEM_EXPAT:BOOL=ON ^ + -D ITK_USE_SYSTEM_HDF5:BOOL=ON ^ + -D ITK_USE_SYSTEM_JPEG:BOOL=ON ^ + -D ITK_USE_SYSTEM_PNG:BOOL=ON ^ + -D ITK_USE_SYSTEM_TIFF:BOOL=ON ^ + -D ITK_USE_SYSTEM_ZLIB:BOOL=ON ^ + -D ITK_USE_SYSTEM_FFTW:BOOL=ON ^ + -D ITK_USE_SYSTEM_EIGEN:BOOL=ON ^ + -D ITK_USE_FFTWD:BOOL=ON ^ + -D ITK_USE_FFTWF:BOOL=ON ^ + ^ + -D ITK_BUILD_DEFAULT_MODULES:BOOL=ON ^ + -D Module_ITKReview:BOOL=ON ^ + -D Module_ITKTBB:BOOL=ON ^ + -D Module_MGHIO:BOOL=ON ^ + -D Module_ITKIOTransformMINC:BOOL=ON ^ + -D Module_GenericLabelInterpolator:BOOL=ON ^ + -D Module_AdaptiveDenoising:BOOL=ON ^ + ^ + -D ITK_USE_KWSTYLE:BOOL=OFF ^ + -D "ITK_DEFAULT_THREADER:STRING=Pool" ^ + ^ + "%SRC_DIR%" + +if errorlevel 1 exit /b 1 + +cmake --build . --config Release +if errorlevel 1 exit /b 1 + +cmake --install . --config Release +if errorlevel 1 exit /b 1 diff --git a/packages/libitk-wrapping/build-libitk-wrapping.sh b/packages/libitk-wrapping/build-libitk-wrapping.sh new file mode 100755 index 00000000..994c6c4f --- /dev/null +++ b/packages/libitk-wrapping/build-libitk-wrapping.sh @@ -0,0 +1,77 @@ +#!/bin/bash +set -euo pipefail + +# Build ITK C++ with Python wrapping for use as a conda package. +# This produces headers, shared libraries, CMake config, and all +# wrapping metadata (SWIG .i/.idx/.mdx files, Python stubs) needed +# by downstream ITK remote modules. + +BUILD_DIR="${SRC_DIR}/../build" +mkdir -p "${BUILD_DIR}" +cd "${BUILD_DIR}" + +# Use TBB on Linux; macOS has known issues with conda TBB +use_tbb=ON +if [ "$(uname)" = "Darwin" ]; then + use_tbb=OFF +fi + +# Handle cross-compilation try-run results if available +if [[ "${CONDA_BUILD_CROSS_COMPILATION:-0}" == "1" ]]; then + try_run_results="${RECIPE_DIR}/TryRunResults-${target_platform}.cmake" + if [[ -f "${try_run_results}" ]]; then + CMAKE_ARGS="${CMAKE_ARGS} -C ${try_run_results}" + fi +fi + +cmake \ + -G "Ninja" \ + ${CMAKE_ARGS} \ + -D BUILD_SHARED_LIBS:BOOL=ON \ + -D BUILD_TESTING:BOOL=OFF \ + -D BUILD_EXAMPLES:BOOL=OFF \ + -D CMAKE_BUILD_TYPE:STRING=Release \ + -D "CMAKE_INSTALL_PREFIX=${PREFIX}" \ + \ + -D ITK_WRAP_PYTHON:BOOL=ON \ + -D ITK_WRAP_DOC:BOOL=ON \ + -D ITK_LEGACY_SILENT:BOOL=ON \ + -D CMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON \ + \ + -D ITK_WRAP_unsigned_short:BOOL=ON \ + -D ITK_WRAP_double:BOOL=ON \ + -D ITK_WRAP_complex_double:BOOL=ON \ + -D "ITK_WRAP_IMAGE_DIMS:STRING=2;3;4" \ + \ + -D WRAP_ITK_INSTALL_COMPONENT_IDENTIFIER:STRING=PythonWheel \ + -D WRAP_ITK_INSTALL_COMPONENT_PER_MODULE:BOOL=ON \ + \ + -D ITK_USE_SYSTEM_EXPAT:BOOL=ON \ + -D ITK_USE_SYSTEM_HDF5:BOOL=ON \ + -D ITK_USE_SYSTEM_JPEG:BOOL=ON \ + -D ITK_USE_SYSTEM_PNG:BOOL=ON \ + -D ITK_USE_SYSTEM_TIFF:BOOL=ON \ + -D ITK_USE_SYSTEM_ZLIB:BOOL=ON \ + -D ITK_USE_SYSTEM_FFTW:BOOL=ON \ + -D ITK_USE_SYSTEM_EIGEN:BOOL=ON \ + -D ITK_USE_FFTWD:BOOL=ON \ + -D ITK_USE_FFTWF:BOOL=ON \ + \ + -D ITK_BUILD_DEFAULT_MODULES:BOOL=ON \ + -D Module_ITKReview:BOOL=ON \ + -D Module_ITKTBB:BOOL=${use_tbb} \ + -D Module_MGHIO:BOOL=ON \ + -D Module_ITKIOTransformMINC:BOOL=ON \ + -D Module_GenericLabelInterpolator:BOOL=ON \ + -D Module_AdaptiveDenoising:BOOL=ON \ + \ + -D ITK_USE_KWSTYLE:BOOL=OFF \ + -D NIFTI_SYSTEM_MATH_LIB= \ + -D GDCM_USE_COREFOUNDATION_LIBRARY:BOOL=OFF \ + -D "ITK_DEFAULT_THREADER:STRING=Pool" \ + \ + "${SRC_DIR}" + +cmake --build . --config Release + +cmake --install . --config Release diff --git a/packages/libitk-wrapping/pixi.toml b/packages/libitk-wrapping/pixi.toml new file mode 100644 index 00000000..6bf85641 --- /dev/null +++ b/packages/libitk-wrapping/pixi.toml @@ -0,0 +1,15 @@ +[workspace] +channels = ["https://prefix.dev/conda-forge"] +platforms = ["linux-64", "linux-aarch64", "osx-arm64", "osx-64", "win-64"] +preview = ["pixi-build"] + +[dependencies] +libitk-wrapping = { path = "." } +python = ">=3.10" + +[package] +name = "libitk-wrapping" +version = "6.99.0" + +[package.build] +backend = { name = "pixi-build-rattler-build", version = "0.3.*" } diff --git a/packages/libitk-wrapping/recipe.yaml b/packages/libitk-wrapping/recipe.yaml new file mode 100644 index 00000000..9cfe7a5b --- /dev/null +++ b/packages/libitk-wrapping/recipe.yaml @@ -0,0 +1,56 @@ +package: + name: libitk-wrapping + version: "6.99.0" + +source: + git: ${{ env.get("ITK_GIT_URL", "https://github.com/BRAINSia/ITK.git") }} + tag: ${{ env.get("ITK_GIT_TAG", "itk-conda-pythonpackage-support") }} + +build: + number: 0 + script: + - if: unix + then: bash ${RECIPE_DIR}/build-libitk-wrapping.sh + - if: win + then: cmd /c ${RECIPE_DIR}/build-libitk-wrapping.bat + +requirements: + build: + - ${{ compiler('c') }} + - ${{ compiler('cxx') }} + - cmake >=3.26 + - ninja + host: + - python + - swig >=4.1 + - castxml + - expat + - hdf5 + - libjpeg-turbo + - libtiff + - libpng + - eigen + - zlib + - fftw + - tbb-devel + - doxygen + run: + - python + - tbb + - hdf5 + - fftw + - libjpeg-turbo + - libtiff + - libpng + - expat + - zlib + +about: + home: https://itk.org + license: Apache-2.0 + license_file: LICENSE + summary: > + ITK C++ libraries with Python wrapping artifacts (SWIG interfaces, + CastXML outputs, compiled Python modules). Used as a build dependency + for ITK Python wheel generation and remote module packaging. + dev_url: https://github.com/InsightSoftwareConsortium/ITK diff --git a/pixi.lock b/pixi.lock new file mode 100644 index 00000000..e1622f65 --- /dev/null +++ b/pixi.lock @@ -0,0 +1,13400 @@ +version: 6 +environments: + default: + channels: + - url: https://conda.anaconda.org/conda-forge/ + options: + pypi-prerelease-mode: if-necessary-or-explicit + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py314h3de4e8d_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py314h4a8dc5f_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.1.1-py314hdafbbf9_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cpp-expected-1.3.1-h171cf75_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-hff5e90c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/frozendict-2.4.7-py314h5bd0f2a_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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-78.2-h33c6efd_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.0.0-pyhcf101f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.6-gpl_hc2c16d8_100.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.19.0-hcf29cc6_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.4-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-2.5.0-hd28c85e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-spdlog-2.5.0-h12fcf84_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.5.0-py314hcbd71af_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.67.0-had1ee68_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsolv-0.7.35-h9463b59_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-16-2.15.2-hca6bf5a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.2-he237659_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/linux-64/lz4-c-1.10.0-h5888daf_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-h280c20c_1002.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/menuinst-2.4.2-py314hdafbbf9_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.1.2-py314h9891dd4_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pycosat-0.6.6-py314h5bd0f2a_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.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.14.3-h32b2ec7_101_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py314h67df5f8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-14.2.5.post0-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-cpp-14.2.5.post0-h5888daf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml-0.18.17-py314h0f05182_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml.clib-0.2.15-py314h0f05182_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/simdjson-4.2.4-hb700be7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/spdlog-1.17.0-hab81395_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/taplo-0.10.0-h2d22210_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.1.0-py314h9891dd4_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_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/linux-64/yaml-cpp-0.8.0-h3f2d84a_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py314h0f05182_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + linux-aarch64: + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-python-1.2.0-py314h352cb57_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/c-ares-1.34.6-he30d5cf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cffi-2.0.0-py314h0bd77cf_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/conda-26.1.1-py314h28a4750_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cpp-expected-1.3.1-hdc560ac_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/fmt-12.1.0-h20c602a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/frozendict-2.4.7-py314h51f160d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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-aarch64/icu-78.2-hcab7f73_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.0.0-pyhcf101f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/keyutils-1.6.3-h86ecc28_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/krb5-1.22.2-hfd895c2_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.45.1-default_h1979696_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libarchive-3.8.6-gpl_hbe7d12b_100.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcurl-8.19.0-hc57f145_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libedit-3.1.20250104-pl5321h976ea20_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libev-4.33-h31becfc_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.7.4-hfae3067_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-15.2.0-he9431aa_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libiconv-1.18-h90929bb_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.2-he30d5cf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmamba-2.5.0-hc712cdd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmamba-spdlog-2.5.0-h3ad78e7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmambapy-2.5.0-py314h709e558_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmpdec-4.0.0-he30d5cf_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libnghttp2-1.67.0-ha888d0e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsolv-0.7.35-hdda61c4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.52.0-h10b116e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libssh2-1.11.1-h18c354c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.41.3-h1022ec0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-16-2.15.2-h79dcc73_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-2.15.2-h825857f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.1-h86ecc28_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lz4-c-1.10.0-h5ad3122_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lzo-2.10-h80f16a2_1002.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/menuinst-2.4.2-py314h28a4750_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/msgpack-python-1.1.2-py314hd7d8586_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.5-ha32ae93_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.1-h546c87b_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pycosat-0.6.6-py314h51f160d_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.3-hb06a95a_101_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py314h807365f_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/reproc-14.2.5.post0-h86ecc28_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/reproc-cpp-14.2.5.post0-h5ad3122_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruamel.yaml-0.18.17-py314h2e8dab5_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruamel.yaml.clib-0.2.15-py314h2e8dab5_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/simdjson-4.2.4-hfefdfc9_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/spdlog-1.17.0-h9f97df7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/taplo-0.10.0-h3618846_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h0dc03b3_103.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ukkonen-1.1.0-py314hd7d8586_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-0.2.5-h80f16a2_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-cpp-0.8.0-h5ad3122_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstandard-0.25.0-py314h2e8dab5_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda + osx-64: + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/brotli-python-1.2.0-py314h3262eb8_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_9.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.34.6-hb5e19a0_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cffi-2.0.0-py314h8ca4d5a_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/conda-26.1.1-py314hee6578b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cpp-expected-1.3.1-h0ba0a54_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/fmt-12.1.0-hda137b5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/frozendict-2.4.7-py314h6482030_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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-64/icu-78.2-h14c5de8_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.0.0-pyhcf101f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/krb5-1.22.2-h207b36a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libarchive-3.8.6-gpl_h2bf6321_100.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcurl-8.19.0-h8f0b9e4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-22.1.1-h19cb2f5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libedit-3.1.20250104-pl5321ha958ccf_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libev-4.33-h10d778d_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.7.4-h991f03e_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.5.2-hd1f9c09_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.18-h57a12c2_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.2-h11316ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libmamba-2.5.0-h7fe6c55_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libmamba-spdlog-2.5.0-hb923e0c_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libmambapy-2.5.0-py314haca2e77_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libmpdec-4.0.0-hf3981d6_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.67.0-h3338091_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsolv-0.7.35-h6fd32b5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.52.0-h77d7759_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.11.1-hed3591d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libxml2-16-2.15.2-h7a90416_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.15.2-hd552753_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.1-hd23fc13_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/lz4-c-1.10.0-h240833e_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/lzo-2.10-h4132b18_1002.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/menuinst-2.4.2-py314hee6578b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/msgpack-python-1.1.2-py314h00ed6fe_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-h0622a9a_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.6.1-hb6871ef_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/pycosat-0.6.6-py314h03d016b_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.14.3-h4f44bb5_101_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/pyyaml-6.0.3-py314h10d0514_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/reproc-14.2.5.post0-h6e16a3a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/reproc-cpp-14.2.5.post0-h240833e_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml-0.18.17-py314hd330473_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml.clib-0.2.15-py314hd330473_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/simdjson-4.2.4-hcb651aa_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/spdlog-1.17.0-h30f01e4_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/taplo-0.10.0-hffa81eb_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h7142dee_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ukkonen-1.1.0-py314h473ef84_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/yaml-0.2.5-h4132b18_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/yaml-cpp-0.8.0-h92383a6_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/zstandard-0.25.0-py314hd1e8ddb_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-h3eecb57_6.conda + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.2.0-py314h3daef5d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-2.0.0-py314h44086f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/conda-26.1.1-py314h4dc9dd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cpp-expected-1.3.1-h4f10f1e_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/fmt-12.1.0-h403dcb5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/frozendict-2.4.7-py314h0612a62_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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-78.2-hef89b57_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.0.0-pyhcf101f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libarchive-3.8.6-gpl_h6fbacd7_100.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.19.0-hd5a2499_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.1-h55c6f16_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.4-hf6b4638_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_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/liblzma-5.8.2-h8088a28_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmamba-2.5.0-h7950639_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmamba-spdlog-2.5.0-h85b9800_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmambapy-2.5.0-py314hf8f60b7_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.67.0-hc438710_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsolv-0.7.35-h5f525b2_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.52.0-h1ae2325_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/libxml2-16-2.15.2-h5ef1a60_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-2.15.2-h8d039ee_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/lz4-c-1.10.0-h286801f_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lzo-2.10-h925e9cb_1002.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/menuinst-2.4.2-py314h4dc9dd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/msgpack-python-1.1.2-py314h784bc60_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.1-hd24854e_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pycosat-0.6.6-py314hb84d1df_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.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.14.3-h4c637c5_101_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyyaml-6.0.3-py314h6e9b3f0_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/reproc-14.2.5.post0-h5505292_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/reproc-cpp-14.2.5.post0-h286801f_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruamel.yaml-0.18.17-py314ha14b1ff_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruamel.yaml.clib-0.2.15-py314ha14b1ff_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/simdjson-4.2.4-ha7d2532_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/spdlog-1.17.0-ha0f8610_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/taplo-0.10.0-h2b2570c_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ukkonen-1.1.0-py314h6cfcd04_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_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/osx-arm64/yaml-cpp-0.8.0-ha1acc90_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.25.0-py314h9d33bd4_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda + win-64: + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/brotli-python-1.2.0-py314he701e3d_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-h4c7d964_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cffi-2.0.0-py314h5a2d7ad_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/conda-26.1.1-py314h86ab7b2_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cpp-expected-1.3.1-h477610d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/fmt-12.1.0-h7f4e812_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/frozendict-2.4.7-py314h5a2d7ad_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.0.0-pyhcf101f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/krb5-1.22.2-h0ea6238_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libarchive-3.8.6-gpl_he24518a_100.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libcurl-8.19.0-h8206538_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.7.4-hac47afa_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.5.2-h3d046cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libiconv-1.18-hc1393d2_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/liblzma-5.8.2-hfd05255_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libmamba-2.5.0-h06825f5_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libmamba-spdlog-2.5.0-h9ae1bf1_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libmambapy-2.5.0-py314h532c739_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libmpdec-4.0.0-hfd05255_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libsolv-0.7.35-h8883371_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.52.0-hf5d6505_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libssh2-1.11.1-h9aa295b_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-16-2.15.2-h692994f_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-2.15.2-h5d26750_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/lz4-c-1.10.0-h2466b09_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/lzo-2.10-h6a83c73_1002.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/menuinst-2.4.2-py314h13fbf68_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/msgpack-python-1.1.2-py314h909e829_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.1-hf411b9b_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-win_hba80fca_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/pycosat-0.6.6-py314h5a2d7ad_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyh09c184e_7.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.14.3-h4b44e0e_101_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/pyyaml-6.0.3-py314h2359020_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/reproc-14.2.5.post0-h2466b09_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/reproc-cpp-14.2.5.post0-he0c23c2_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ruamel.yaml-0.18.17-py314hc5dbbe4_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ruamel.yaml.clib-0.2.15-py314hc5dbbe4_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/simdjson-4.2.4-h49e36cd_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/spdlog-1.17.0-h9f585f1_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/taplo-0.10.0-h63977a8_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h6ed50ae_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyha7b4d00_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ukkonen-1.1.0-py314h909e829_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vc-14.3-h41ae7f8_34.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.44.35208-h818238b_34.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vcomp14-14.44.35208-h818238b_34.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/win_inet_pton-1.1.0-pyh7428d3b_8.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/yaml-0.2.5-h6a83c73_3.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/yaml-cpp-0.8.0-he0c23c2_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/zstandard-0.25.0-py314hc5dbbe4_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.7-h534d264_6.conda + linux-py310: + channels: + - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple + options: + pypi-prerelease-mode: if-necessary-or-explicit + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/auditwheel-6.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.3.0-py310h69bd2ac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils-2.45.1-default_h4852527_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.45.1-default_hfdba357_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.45.1-default_h4852527_101.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py310hba01987_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-compiler-1.11.0-h4d9bdce_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py310he7384ee_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cmake-3.31.8-hc85cc9f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.1.1-py310hff52083_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-gcc-specs-14.3.0-he8ccf15_18.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cpp-expected-1.3.1-h171cf75_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.11.0-hfcd1e18_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/doxygen-1.13.2-h8e693c7_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-hff5e90c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/frozendict-2.4.7-py310h7c4b9e2_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gcc-14.3.0-h0dff253_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gcc_impl_linux-64-14.3.0-hbdf3cc3_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gcc_linux-64-14.3.0-h298d278_21.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx-14.3.0-h76987e4_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-14.3.0-h2185e75_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_linux-64-14.3.0-he467f4b_21.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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-78.2-h33c6efd_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.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/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.0.0-pyhcf101f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/kernel-headers_linux-64-4.18.0-he073ed8_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.6-gpl_hc2c16d8_100.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-5_h4a7cf45_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-5_h0358290_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.19.0-hcf29cc6_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.4-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_linux-64-14.3.0-hf649bbc_118.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-5_h47877c9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-2.5.0-hd28c85e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-spdlog-2.5.0-h12fcf84_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.5.0-py310h74f1d5f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.67.0-had1ee68_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-14.3.0-h8f1669f_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsolv-0.7.35-h9463b59_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-14.3.0-h9f08a49_118.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.51.0-hb03c661_1.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/libxml2-16-2.15.2-hca6bf5a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.2-he237659_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/linux-64/lz4-c-1.10.0-h5888daf_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-h280c20c_1002.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/menuinst-2.4.2-py310hff52083_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.1.2-py310h03d9f68_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/ninja-1.13.2-h171cf75_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.2.6-py310hefbff90_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/patchelf-0.17.2-h58526e2_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pycosat-0.6.6-py310h7c4b9e2_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyelftools-0.32-pyh707e725_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.11.0-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.10.20-h3c07f61_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.10-8_cp310.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py310h3406613_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-14.2.5.post0-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-cpp-14.2.5.post0-h5888daf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/rhash-1.4.6-hb9d3cd8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml-0.18.17-py310h139afa4_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml.clib-0.2.15-py310h139afa4_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-0.11.6-pyh7e86bf3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-9.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools_scm-9.2.2-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/simdjson-4.2.4-hb700be7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/spdlog-1.17.0-hab81395_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.28-h4ee821c_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/taplo-0.10.0-h2d22210_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.1.0-py310h03d9f68_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_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/linux-64/yaml-cpp-0.8.0-h3f2d84a_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py310h139afa4_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + - pypi: https://files.pythonhosted.org/packages/c5/0d/84a4380f930db0010168e0aa7b7a8fed9ba1835a8fbb1472bc6d0201d529/build-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl + linux-aarch64: + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/auditwheel-6.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/backports.zstd-1.3.0-py310hfa1aa29_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/binutils-2.45.1-default_hf1166c9_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/binutils_impl_linux-aarch64-2.45.1-default_h5f4c503_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/binutils_linux-aarch64-2.45.1-default_hf1166c9_101.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-python-1.2.0-py310hbe54bbb_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/c-ares-1.34.6-he30d5cf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/c-compiler-1.11.0-hdceaead_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cffi-2.0.0-py310h0826a50_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cmake-3.31.8-hc9d863e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/conda-26.1.1-py310h4c7bcd0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/conda-gcc-specs-14.3.0-hadff5d6_18.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cpp-expected-1.3.1-hdc560ac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cxx-compiler-1.11.0-h7b35c40_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/doxygen-1.13.2-h5e0f5ae_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/fmt-12.1.0-h20c602a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/frozendict-2.4.7-py310h5b55623_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gcc-14.3.0-h2e72a27_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gcc_impl_linux-aarch64-14.3.0-h533bfc8_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gcc_linux-aarch64-14.3.0-h118592a_21.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gxx-14.3.0-ha384071_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gxx_impl_linux-aarch64-14.3.0-h0d4f5d4_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gxx_linux-aarch64-14.3.0-h32e4f2e_21.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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-aarch64/icu-78.3-hcab7f73_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.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/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.0.0-pyhcf101f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/kernel-headers_linux-aarch64-4.18.0-h05a177a_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/keyutils-1.6.3-h86ecc28_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/krb5-1.22.2-hfd895c2_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.45.1-default_h1979696_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libarchive-3.8.6-gpl_hbe7d12b_100.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libblas-3.11.0-5_haddc8a3_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcblas-3.11.0-5_hd72aa62_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcurl-8.19.0-hc57f145_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libedit-3.1.20250104-pl5321h976ea20_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libev-4.33-h31becfc_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.7.4-hfae3067_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_18.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_linux-aarch64-14.3.0-h25ba3ff_118.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-15.2.0-he9431aa_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran-15.2.0-he9431aa_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran5-15.2.0-h1b7bec0_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libhwloc-2.13.0-default_ha95e27d_1000.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libiconv-1.18-h90929bb_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblapack-3.11.0-5_h88aeb00_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.2-he30d5cf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmamba-2.5.0-hc712cdd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmamba-spdlog-2.5.0-h3ad78e7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmambapy-2.5.0-py310hdf79504_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libnghttp2-1.68.1-hd3077d7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libnsl-2.0.1-h86ecc28_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopenblas-0.3.30-pthreads_h9d3fd7e_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsanitizer-14.3.0-hedb4206_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsolv-0.7.36-hdda61c4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.52.0-h10b116e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libssh2-1.11.1-h18c354c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_18.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-aarch64-14.3.0-h57c8d61_118.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-ng-15.2.0-hdbbeba8_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.41.3-h1022ec0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuv-1.51.0-he30d5cf_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxcrypt-4.4.36-h31becfc_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-16-2.15.2-h79dcc73_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-2.15.2-h825857f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.1-h86ecc28_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lz4-c-1.10.0-h5ad3122_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lzo-2.10-h80f16a2_1002.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/menuinst-2.4.2-py310h4c7bcd0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/msgpack-python-1.1.2-py310h0992a49_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.5-ha32ae93_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ninja-1.13.2-hdc560ac_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/numpy-2.2.6-py310h6e5608f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.1-h546c87b_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/patchelf-0.17.2-h884eca8_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pycosat-0.6.6-py310h5b55623_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyelftools-0.32-pyh707e725_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.11.0-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-aarch64/python-3.10.20-h28be5d3_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.10-8_cp310.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py310h2d8da20_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/reproc-14.2.5.post0-h86ecc28_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/reproc-cpp-14.2.5.post0-h5ad3122_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/rhash-1.4.6-h86ecc28_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruamel.yaml-0.18.17-py310hef25091_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruamel.yaml.clib-0.2.15-py310hef25091_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-0.11.6-pyh7e86bf3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-9.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools_scm-9.2.2-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/simdjson-4.2.4-hfefdfc9_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/spdlog-1.17.0-h9f97df7_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-aarch64-2.28-h585391f_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/taplo-0.10.0-h3618846_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h0dc03b3_103.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ukkonen-1.1.0-py310h0992a49_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-0.2.5-h80f16a2_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-cpp-0.8.0-h5ad3122_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstandard-0.25.0-py310hef25091_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda + - pypi: https://files.pythonhosted.org/packages/c5/0d/84a4380f930db0010168e0aa7b7a8fed9ba1835a8fbb1472bc6d0201d529/build-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl + linux-py311: + channels: + - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple + options: + pypi-prerelease-mode: if-necessary-or-explicit + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/auditwheel-6.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.3.0-py311h6b1f9c4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils-2.45.1-default_h4852527_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.45.1-default_hfdba357_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.45.1-default_h4852527_101.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py311h66f275b_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-compiler-1.11.0-h4d9bdce_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py311h03d9500_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cmake-3.31.8-hc85cc9f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.1.1-py311h38be061_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-gcc-specs-14.3.0-he8ccf15_18.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cpp-expected-1.3.1-h171cf75_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.11.0-hfcd1e18_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/doxygen-1.13.2-h8e693c7_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-hff5e90c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/frozendict-2.4.7-py311h49ec1c0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gcc-14.3.0-h0dff253_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gcc_impl_linux-64-14.3.0-hbdf3cc3_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gcc_linux-64-14.3.0-h298d278_21.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx-14.3.0-h76987e4_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-14.3.0-h2185e75_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_linux-64-14.3.0-he467f4b_21.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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-78.2-h33c6efd_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.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/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.0.0-pyhcf101f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/kernel-headers_linux-64-4.18.0-he073ed8_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.6-gpl_hc2c16d8_100.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-5_h4a7cf45_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-5_h0358290_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.19.0-hcf29cc6_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.4-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_linux-64-14.3.0-hf649bbc_118.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-5_h47877c9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-2.5.0-hd28c85e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-spdlog-2.5.0-h12fcf84_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.5.0-py311hc5d5c7c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.67.0-had1ee68_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-14.3.0-h8f1669f_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsolv-0.7.35-h9463b59_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-14.3.0-h9f08a49_118.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.51.0-hb03c661_1.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/libxml2-16-2.15.2-hca6bf5a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.2-he237659_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/linux-64/lz4-c-1.10.0-h5888daf_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-h280c20c_1002.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/menuinst-2.4.2-py311h38be061_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.1.2-py311hdf67eae_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/ninja-1.13.2-h171cf75_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.2-py311h2e04523_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/patchelf-0.17.2-h58526e2_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pycosat-0.6.6-py311h49ec1c0_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyelftools-0.32-pyh707e725_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.11.0-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.11.15-hd63d673_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py311h3778330_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-14.2.5.post0-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-cpp-14.2.5.post0-h5888daf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/rhash-1.4.6-hb9d3cd8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml-0.18.17-py311haee01d2_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml.clib-0.2.15-py311haee01d2_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-0.11.6-pyh7e86bf3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-9.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools_scm-9.2.2-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/simdjson-4.2.4-hb700be7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/spdlog-1.17.0-hab81395_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.28-h4ee821c_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/taplo-0.10.0-h2d22210_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.1.0-py311hdf67eae_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_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/linux-64/yaml-cpp-0.8.0-h3f2d84a_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py311haee01d2_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + - pypi: https://files.pythonhosted.org/packages/c5/0d/84a4380f930db0010168e0aa7b7a8fed9ba1835a8fbb1472bc6d0201d529/build-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl + linux-aarch64: + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/auditwheel-6.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/backports.zstd-1.3.0-py311h6ce31b0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/binutils-2.45.1-default_hf1166c9_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/binutils_impl_linux-aarch64-2.45.1-default_h5f4c503_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/binutils_linux-aarch64-2.45.1-default_hf1166c9_101.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-python-1.2.0-py311h14a79a7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/c-ares-1.34.6-he30d5cf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/c-compiler-1.11.0-hdceaead_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cffi-2.0.0-py311h460c349_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cmake-3.31.8-hc9d863e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/conda-26.1.1-py311hec3470c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/conda-gcc-specs-14.3.0-hadff5d6_18.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cpp-expected-1.3.1-hdc560ac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cxx-compiler-1.11.0-h7b35c40_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/doxygen-1.13.2-h5e0f5ae_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/fmt-12.1.0-h20c602a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/frozendict-2.4.7-py311h19352d5_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gcc-14.3.0-h2e72a27_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gcc_impl_linux-aarch64-14.3.0-h533bfc8_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gcc_linux-aarch64-14.3.0-h118592a_21.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gxx-14.3.0-ha384071_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gxx_impl_linux-aarch64-14.3.0-h0d4f5d4_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gxx_linux-aarch64-14.3.0-h32e4f2e_21.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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-aarch64/icu-78.3-hcab7f73_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.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/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.0.0-pyhcf101f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/kernel-headers_linux-aarch64-4.18.0-h05a177a_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/keyutils-1.6.3-h86ecc28_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/krb5-1.22.2-hfd895c2_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.45.1-default_h1979696_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libarchive-3.8.6-gpl_hbe7d12b_100.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libblas-3.11.0-5_haddc8a3_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcblas-3.11.0-5_hd72aa62_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcurl-8.19.0-hc57f145_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libedit-3.1.20250104-pl5321h976ea20_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libev-4.33-h31becfc_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.7.4-hfae3067_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_18.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_linux-aarch64-14.3.0-h25ba3ff_118.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-15.2.0-he9431aa_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran-15.2.0-he9431aa_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran5-15.2.0-h1b7bec0_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libhwloc-2.13.0-default_ha95e27d_1000.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libiconv-1.18-h90929bb_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblapack-3.11.0-5_h88aeb00_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.2-he30d5cf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmamba-2.5.0-hc712cdd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmamba-spdlog-2.5.0-h3ad78e7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmambapy-2.5.0-py311h6a8bf82_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libnghttp2-1.68.1-hd3077d7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libnsl-2.0.1-h86ecc28_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopenblas-0.3.30-pthreads_h9d3fd7e_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsanitizer-14.3.0-hedb4206_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsolv-0.7.36-hdda61c4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.52.0-h10b116e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libssh2-1.11.1-h18c354c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_18.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-aarch64-14.3.0-h57c8d61_118.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-ng-15.2.0-hdbbeba8_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.41.3-h1022ec0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuv-1.51.0-he30d5cf_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxcrypt-4.4.36-h31becfc_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-16-2.15.2-h79dcc73_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-2.15.2-h825857f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.1-h86ecc28_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lz4-c-1.10.0-h5ad3122_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lzo-2.10-h80f16a2_1002.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/menuinst-2.4.2-py311hec3470c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/msgpack-python-1.1.2-py311hfca10b7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.5-ha32ae93_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ninja-1.13.2-hdc560ac_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/numpy-2.4.3-py311h669026d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.1-h546c87b_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/patchelf-0.17.2-h884eca8_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pycosat-0.6.6-py311h19352d5_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyelftools-0.32-pyh707e725_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.11.0-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-aarch64/python-3.11.15-h91f4b29_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py311h164a683_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/reproc-14.2.5.post0-h86ecc28_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/reproc-cpp-14.2.5.post0-h5ad3122_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/rhash-1.4.6-h86ecc28_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruamel.yaml-0.18.17-py311h51cfe5d_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruamel.yaml.clib-0.2.15-py311h51cfe5d_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-0.11.6-pyh7e86bf3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-9.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools_scm-9.2.2-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/simdjson-4.2.4-hfefdfc9_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/spdlog-1.17.0-h9f97df7_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-aarch64-2.28-h585391f_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/taplo-0.10.0-h3618846_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h0dc03b3_103.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ukkonen-1.1.0-py311hfca10b7_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-0.2.5-h80f16a2_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-cpp-0.8.0-h5ad3122_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstandard-0.25.0-py311h51cfe5d_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda + - pypi: https://files.pythonhosted.org/packages/c5/0d/84a4380f930db0010168e0aa7b7a8fed9ba1835a8fbb1472bc6d0201d529/build-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl + macosx-py310: + channels: + - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple + options: + pypi-prerelease-mode: if-necessary-or-explicit + packages: + osx-64: + - conda: https://conda.anaconda.org/conda-forge/osx-64/_openmp_mutex-4.5-7_kmp_llvm.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/brotli-python-1.1.0-py310h9e9d8ca_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h10d778d_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.28.1-h10d778d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/c-compiler-1.10.0-h09a7c41_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools-986-hd3558d4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools_osx-64-986-h58a35ae_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cffi-1.16.0-py310hdca579f_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-18-18.1.3-default_h7151d67_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-18.1.3-default_h7151d67_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_impl_osx-64-18.1.3-hdbcc6ac_11.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_osx-64-18.1.3-hb91bd55_11.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx-18.1.3-default_h7151d67_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_impl_osx-64-18.1.3-h5bc21ce_11.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_osx-64-18.1.3-hb91bd55_11.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cmake-3.27.6-hf40c264_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/compiler-rt-18.1.3-ha38d28d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-64-18.1.3-ha38d28d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/conda-23.9.0-py310h2ec42d9_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cryptography-41.0.7-py310h527a09d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cxx-compiler-1.10.0-h20888b2_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/doxygen-1.10.0-h5ff76d1_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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-64/icu-73.2-hf5e326d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.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/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.0.0-pyhcf101f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/krb5-1.21.2-hb884880_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ld64-711-h4e51db5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ld64_osx-64-711-had5d0d3_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.9.0-22_osx64_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.9.0-22_osx64_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libclang-cpp18.1-18.1.3-default_h7151d67_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcurl-8.4.0-h726d00d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-16.0.6-hd57cbcb_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libedit-3.1.20191231-h0678c8f_2.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/libev-4.33-h10d778d_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.6.2-h73e2aa4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.4.2-h0d85af4_5.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgcc-15.2.0-h08519bb_18.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.2.0-h7e5c614_18.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.2.0-hd16e46c_18.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.17-hd75f5a5_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.9.0-22_osx64_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libllvm18-18.1.3-hbcf5fad_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.52.0-he2ab024_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.27-openmp_hfef2a42_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.45.3-h92b6c6a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.11.0-hd019ec5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libuv-1.48.0-h67532ce_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.12.6-hc0ae0f7_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.1-hd75f5a5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-18.1.3-hb6ac08f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-18.1.3-hbcf5fad_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-h5846eda_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ninja-1.12.0-h7728843_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-1.26.4-py310h4bfa8fc_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.3.0-hd75f5a5_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/pycosat-0.6.6-py310h6729b98_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyopenssl-25.1.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.11.0-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/osx-64/python-3.10.14-h00d2728_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.10-8_cp310.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/pyyaml-6.0.1-py310h6729b98_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h7cca4af_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/rhash-1.4.4-h0dc2134_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml-0.17.40-py310hb372a2b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml.clib-0.2.8-py310hb372a2b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-0.11.6-pyh7e86bf3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-9.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools_scm-9.2.2-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/sigtool-0.1.3-h88f4db0_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/tapi-1100.0.11-h9ce4665_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/taplo-0.8.1-h7205ca4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h1abcd95_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ukkonen-1.0.1-py310h88cfcbd_4.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-21.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/xz-5.2.6-h775f41a_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/yaml-0.2.5-h0d85af4_2.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/zstandard-0.22.0-py310hd88f66e_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.5-h829000d_0.conda + - pypi: https://files.pythonhosted.org/packages/a9/ba/000a1996d4308bc65120167c21241a3b205464a2e0b58deda26ae8ac21d1/altgraph-0.17.5-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c5/0d/84a4380f930db0010168e0aa7b7a8fed9ba1835a8fbb1472bc6d0201d529/build-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2b/dd/437e601fa9d2b6bf8507256daf52196a226c3b340261f4cde8fac8e853ea/delocate-0.13.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c7/d1/a9f36f8ecdf0fb7c9b1e78c8d7af12b8c8754e74851ac7b94a8305540fc7/macholib-1.16.4-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/_openmp_mutex-4.5-7_kmp_llvm.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.1.0-py310h1253130_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h93a5062_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.28.1-h93a5062_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-compiler-1.10.0-hdf49b6b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cctools-986-h4c9edd9_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cctools_osx-arm64-986-hd11630f_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-1.16.0-py310hdcd7c05_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-18-18.1.3-default_he012953_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-18.1.3-default_h4cf2255_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang_impl_osx-arm64-18.1.3-hda94301_11.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang_osx-arm64-18.1.3-h54d7cd3_11.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx-18.1.3-default_h4cf2255_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx_impl_osx-arm64-18.1.3-h1ba0cb9_11.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx_osx-arm64-18.1.3-h54d7cd3_11.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmake-3.27.6-h1c59155_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/compiler-rt-18.1.3-h3808999_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-arm64-18.1.3-h3808999_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/conda-23.9.0-py310hbe9552e_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cryptography-41.0.7-py310h4c55245_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cxx-compiler-1.10.0-hba80287_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/doxygen-1.10.0-h8fbad5d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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-73.2-hc8870d7_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.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/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.0.0-pyhcf101f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.21.2-h92f50d5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ld64-711-h4c6efb1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ld64_osx-arm64-711-h5e7191b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.9.0-24_osxarm64_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.9.0-24_osxarm64_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libclang-cpp18.1-18.1.3-default_he012953_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.4.0-h2d989ff_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-16.0.6-h4653b0c_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20191231-hc8eb9b7_2.tar.bz2 + - 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.6.2-hebf3989_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.2-h3422bc3_5.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-15.2.0-hcbb3090_18.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.2.0-h07b0088_18.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.2.0-hdae7583_18.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.17-h0d3ecfb_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.9.0-24_osxarm64_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libllvm18-18.1.3-h30cc82d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.52.0-hae82a92_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.27-openmp_h6c19121_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.45.3-h091b4b1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.0-h7a5bd25_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.48.0-h93a5062_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-2.12.6-h35eab27_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-h0d3ecfb_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-18.1.3-hcd81f8e_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-tools-18.1.3-h30cc82d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-hb89a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ninja-1.12.0-h2ffa867_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-1.26.4-py310hd45542a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.3.0-h0d3ecfb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pycosat-0.6.6-py310h2aa6e3c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyopenssl-25.1.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.11.0-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/osx-arm64/python-3.10.14-h2469fbe_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.10-8_cp310.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyyaml-6.0.1-py310h2aa6e3c_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h1d1bf99_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/rhash-1.4.4-hb547adb_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruamel.yaml-0.17.40-py310hd125d64_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruamel.yaml.clib-0.2.8-py310hd125d64_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-0.11.6-pyh7e86bf3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-9.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools_scm-9.2.2-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/sigtool-0.1.3-h44b9a77_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tapi-1100.0.11-he4954df_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/taplo-0.8.1-h69fbcac_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ukkonen-1.0.1-py310h38f39d4_4.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-21.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h3422bc3_2.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.22.0-py310h6289e41_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.5-h4f39d0f_0.conda + - pypi: https://files.pythonhosted.org/packages/a9/ba/000a1996d4308bc65120167c21241a3b205464a2e0b58deda26ae8ac21d1/altgraph-0.17.5-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c5/0d/84a4380f930db0010168e0aa7b7a8fed9ba1835a8fbb1472bc6d0201d529/build-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2b/dd/437e601fa9d2b6bf8507256daf52196a226c3b340261f4cde8fac8e853ea/delocate-0.13.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c7/d1/a9f36f8ecdf0fb7c9b1e78c8d7af12b8c8754e74851ac7b94a8305540fc7/macholib-1.16.4-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl + macosx-py311: + channels: + - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple + options: + pypi-prerelease-mode: if-necessary-or-explicit + packages: + osx-64: + - conda: https://conda.anaconda.org/conda-forge/osx-64/_openmp_mutex-4.5-7_kmp_llvm.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/brotli-python-1.1.0-py311hdf8f085_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h10d778d_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.28.1-h10d778d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/c-compiler-1.10.0-h09a7c41_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools-986-hd3558d4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cctools_osx-64-986-h58a35ae_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cffi-1.16.0-py311hc0b63fd_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-18-18.1.3-default_h7151d67_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang-18.1.3-default_h7151d67_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_impl_osx-64-18.1.3-hdbcc6ac_11.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clang_osx-64-18.1.3-hb91bd55_11.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx-18.1.3-default_h7151d67_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_impl_osx-64-18.1.3-h5bc21ce_11.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_osx-64-18.1.3-hb91bd55_11.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cmake-3.27.6-hf40c264_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/compiler-rt-18.1.3-ha38d28d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-64-18.1.3-ha38d28d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/conda-23.9.0-py311h6eed73b_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cryptography-41.0.7-py311h48c7838_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cxx-compiler-1.10.0-h20888b2_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/doxygen-1.10.0-h5ff76d1_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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-64/icu-73.2-hf5e326d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.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/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.0.0-pyhcf101f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/krb5-1.21.2-hb884880_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ld64-711-h4e51db5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ld64_osx-64-711-had5d0d3_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.9.0-22_osx64_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.9.0-22_osx64_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libclang-cpp18.1-18.1.3-default_h7151d67_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcurl-8.4.0-h726d00d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-16.0.6-hd57cbcb_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libedit-3.1.20191231-h0678c8f_2.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/libev-4.33-h10d778d_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.6.2-h73e2aa4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.4.2-h0d85af4_5.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgcc-15.2.0-h08519bb_18.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.2.0-h7e5c614_18.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.2.0-hd16e46c_18.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.17-hd75f5a5_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.9.0-22_osx64_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libllvm18-18.1.3-hbcf5fad_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.52.0-he2ab024_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.27-openmp_hfef2a42_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.45.3-h92b6c6a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.11.0-hd019ec5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libuv-1.48.0-h67532ce_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.12.6-hc0ae0f7_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.1-hd75f5a5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-18.1.3-hb6ac08f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-18.1.3-hbcf5fad_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-h5846eda_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ninja-1.12.0-h7728843_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-1.26.4-py311hc43a94b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.3.0-hd75f5a5_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/pycosat-0.6.6-py311h2725bcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyopenssl-25.1.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.11.0-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/osx-64/python-3.11.8-h9f0c242_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/pyyaml-6.0.1-py311h2725bcf_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h7cca4af_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/rhash-1.4.4-h0dc2134_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml-0.17.40-py311he705e18_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml.clib-0.2.8-py311he705e18_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-0.11.6-pyh7e86bf3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-9.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools_scm-9.2.2-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/sigtool-0.1.3-h88f4db0_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/tapi-1100.0.11-h9ce4665_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/taplo-0.8.1-h7205ca4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h1abcd95_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ukkonen-1.0.1-py311h5fe6e05_4.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-21.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/xz-5.2.6-h775f41a_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-64/yaml-0.2.5-h0d85af4_2.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/zstandard-0.22.0-py311hed14148_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.5-h829000d_0.conda + - pypi: https://files.pythonhosted.org/packages/a9/ba/000a1996d4308bc65120167c21241a3b205464a2e0b58deda26ae8ac21d1/altgraph-0.17.5-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c5/0d/84a4380f930db0010168e0aa7b7a8fed9ba1835a8fbb1472bc6d0201d529/build-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2b/dd/437e601fa9d2b6bf8507256daf52196a226c3b340261f4cde8fac8e853ea/delocate-0.13.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c7/d1/a9f36f8ecdf0fb7c9b1e78c8d7af12b8c8754e74851ac7b94a8305540fc7/macholib-1.16.4-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/_openmp_mutex-4.5-7_kmp_llvm.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.1.0-py311ha891d26_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h93a5062_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.28.1-h93a5062_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-compiler-1.10.0-hdf49b6b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cctools-986-h4c9edd9_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cctools_osx-arm64-986-hd11630f_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-1.16.0-py311h4a08483_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-18-18.1.3-default_he012953_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-18.1.3-default_h4cf2255_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang_impl_osx-arm64-18.1.3-hda94301_11.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang_osx-arm64-18.1.3-h54d7cd3_11.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx-18.1.3-default_h4cf2255_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx_impl_osx-arm64-18.1.3-h1ba0cb9_11.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx_osx-arm64-18.1.3-h54d7cd3_11.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmake-3.27.6-h1c59155_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/compiler-rt-18.1.3-h3808999_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-arm64-18.1.3-h3808999_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/conda-23.9.0-py311h267d04e_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cryptography-41.0.7-py311h08c85a6_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cxx-compiler-1.10.0-hba80287_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/doxygen-1.10.0-h8fbad5d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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-73.2-hc8870d7_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.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/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.0.0-pyhcf101f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.21.2-h92f50d5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ld64-711-h4c6efb1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ld64_osx-arm64-711-h5e7191b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.9.0-24_osxarm64_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.9.0-24_osxarm64_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libclang-cpp18.1-18.1.3-default_he012953_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.4.0-h2d989ff_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-16.0.6-h4653b0c_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20191231-hc8eb9b7_2.tar.bz2 + - 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.6.2-hebf3989_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.2-h3422bc3_5.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-15.2.0-hcbb3090_18.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.2.0-h07b0088_18.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.2.0-hdae7583_18.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.17-h0d3ecfb_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.9.0-24_osxarm64_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libllvm18-18.1.3-h30cc82d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.52.0-hae82a92_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.27-openmp_h6c19121_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.45.3-h091b4b1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.0-h7a5bd25_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.48.0-h93a5062_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-2.12.6-h35eab27_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-h0d3ecfb_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-18.1.3-hcd81f8e_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-tools-18.1.3-h30cc82d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-hb89a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ninja-1.12.0-h2ffa867_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-1.26.4-py311h7125741_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.3.0-h0d3ecfb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pycosat-0.6.6-py311heffc1b2_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyopenssl-25.1.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.11.0-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/osx-arm64/python-3.11.8-hdf0ec26_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyyaml-6.0.1-py311heffc1b2_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h1d1bf99_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/rhash-1.4.4-hb547adb_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruamel.yaml-0.17.40-py311h05b510d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruamel.yaml.clib-0.2.8-py311h05b510d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-0.11.6-pyh7e86bf3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-9.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools_scm-9.2.2-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/sigtool-0.1.3-h44b9a77_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tapi-1100.0.11-he4954df_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/taplo-0.8.1-h69fbcac_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ukkonen-1.0.1-py311he4fd1f5_4.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-21.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h3422bc3_2.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.22.0-py311h67b91a1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.5-h4f39d0f_0.conda + - pypi: https://files.pythonhosted.org/packages/a9/ba/000a1996d4308bc65120167c21241a3b205464a2e0b58deda26ae8ac21d1/altgraph-0.17.5-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c5/0d/84a4380f930db0010168e0aa7b7a8fed9ba1835a8fbb1472bc6d0201d529/build-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2b/dd/437e601fa9d2b6bf8507256daf52196a226c3b340261f4cde8fac8e853ea/delocate-0.13.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/c7/d1/a9f36f8ecdf0fb7c9b1e78c8d7af12b8c8754e74851ac7b94a8305540fc7/macholib-1.16.4-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl + manylinux228-py310: + channels: + - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple + options: + pypi-prerelease-mode: if-necessary-or-explicit + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/auditwheel-6.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.3.0-py310h69bd2ac_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py310hba01987_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py310he7384ee_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cmake-3.31.8-hc85cc9f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.1.1-py310hff52083_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cpp-expected-1.3.1-h171cf75_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/doxygen-1.13.2-h8e693c7_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-hff5e90c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/frozendict-2.4.7-py310h7c4b9e2_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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-78.2-h33c6efd_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.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/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.0.0-pyhcf101f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.6-gpl_hc2c16d8_100.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-5_h4a7cf45_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-5_h0358290_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.19.0-hcf29cc6_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.4-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-5_h47877c9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-2.5.0-hd28c85e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-spdlog-2.5.0-h12fcf84_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.5.0-py310h74f1d5f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.67.0-had1ee68_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsolv-0.7.35-h9463b59_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.51.0-hb03c661_1.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/libxml2-16-2.15.2-hca6bf5a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.2-he237659_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/linux-64/lz4-c-1.10.0-h5888daf_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-h280c20c_1002.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/menuinst-2.4.2-py310hff52083_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.1.2-py310h03d9f68_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/ninja-1.13.2-h171cf75_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.2.6-py310hefbff90_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/patchelf-0.17.2-h58526e2_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pycosat-0.6.6-py310h7c4b9e2_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyelftools-0.32-pyh707e725_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.11.0-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.10.20-h3c07f61_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.10-8_cp310.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py310h3406613_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-14.2.5.post0-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-cpp-14.2.5.post0-h5888daf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/rhash-1.4.6-hb9d3cd8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml-0.18.17-py310h139afa4_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml.clib-0.2.15-py310h139afa4_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-0.11.6-pyh7e86bf3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-9.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools_scm-9.2.2-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/simdjson-4.2.4-hb700be7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/spdlog-1.17.0-hab81395_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/taplo-0.10.0-h2d22210_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.1.0-py310h03d9f68_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_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/linux-64/yaml-cpp-0.8.0-h3f2d84a_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py310h139afa4_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + - pypi: https://files.pythonhosted.org/packages/c5/0d/84a4380f930db0010168e0aa7b7a8fed9ba1835a8fbb1472bc6d0201d529/build-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl + linux-aarch64: + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/auditwheel-6.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/backports.zstd-1.3.0-py310hfa1aa29_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-python-1.2.0-py310hbe54bbb_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/c-ares-1.34.6-he30d5cf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cffi-2.0.0-py310h0826a50_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cmake-3.31.8-hc9d863e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/conda-26.1.1-py310h4c7bcd0_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cpp-expected-1.3.1-hdc560ac_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/doxygen-1.13.2-h5e0f5ae_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/fmt-12.1.0-h20c602a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/frozendict-2.4.7-py310h5b55623_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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-aarch64/icu-78.2-hcab7f73_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.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/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.0.0-pyhcf101f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/keyutils-1.6.3-h86ecc28_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/krb5-1.22.2-hfd895c2_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.45.1-default_h1979696_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libarchive-3.8.6-gpl_hbe7d12b_100.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libblas-3.11.0-5_haddc8a3_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcblas-3.11.0-5_hd72aa62_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcurl-8.19.0-hc57f145_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libedit-3.1.20250104-pl5321h976ea20_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libev-4.33-h31becfc_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.7.4-hfae3067_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-15.2.0-he9431aa_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran-15.2.0-he9431aa_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran5-15.2.0-h1b7bec0_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libiconv-1.18-h90929bb_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblapack-3.11.0-5_h88aeb00_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.2-he30d5cf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmamba-2.5.0-hc712cdd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmamba-spdlog-2.5.0-h3ad78e7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmambapy-2.5.0-py310hdf79504_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libnghttp2-1.67.0-ha888d0e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libnsl-2.0.1-h86ecc28_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopenblas-0.3.30-pthreads_h9d3fd7e_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsolv-0.7.36-hdda61c4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.52.0-h10b116e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libssh2-1.11.1-h18c354c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-ng-15.2.0-hdbbeba8_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.41.3-h1022ec0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuv-1.51.0-he30d5cf_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxcrypt-4.4.36-h31becfc_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-16-2.15.2-h79dcc73_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-2.15.2-h825857f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.1-h86ecc28_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lz4-c-1.10.0-h5ad3122_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lzo-2.10-h80f16a2_1002.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/menuinst-2.4.2-py310h4c7bcd0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/msgpack-python-1.1.2-py310h0992a49_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.5-ha32ae93_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ninja-1.13.2-hdc560ac_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/numpy-2.2.6-py310h6e5608f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.1-h546c87b_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/patchelf-0.17.2-h884eca8_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pycosat-0.6.6-py310h5b55623_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyelftools-0.32-pyh707e725_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.11.0-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-aarch64/python-3.10.20-h28be5d3_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.10-8_cp310.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py310h2d8da20_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/reproc-14.2.5.post0-h86ecc28_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/reproc-cpp-14.2.5.post0-h5ad3122_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/rhash-1.4.6-h86ecc28_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruamel.yaml-0.18.17-py310hef25091_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruamel.yaml.clib-0.2.15-py310hef25091_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-0.11.6-pyh7e86bf3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-9.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools_scm-9.2.2-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/simdjson-4.2.4-hfefdfc9_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/spdlog-1.17.0-h9f97df7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/taplo-0.10.0-h3618846_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h0dc03b3_103.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ukkonen-1.1.0-py310h0992a49_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-0.2.5-h80f16a2_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-cpp-0.8.0-h5ad3122_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstandard-0.25.0-py310hef25091_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda + - pypi: https://files.pythonhosted.org/packages/c5/0d/84a4380f930db0010168e0aa7b7a8fed9ba1835a8fbb1472bc6d0201d529/build-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl + manylinux228-py311: + channels: + - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple + options: + pypi-prerelease-mode: if-necessary-or-explicit + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/auditwheel-6.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.3.0-py311h6b1f9c4_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py311h66f275b_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py311h03d9500_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cmake-3.31.8-hc85cc9f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.1.1-py311h38be061_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cpp-expected-1.3.1-h171cf75_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/doxygen-1.13.2-h8e693c7_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-hff5e90c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/frozendict-2.4.7-py311h49ec1c0_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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-78.2-h33c6efd_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.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/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.0.0-pyhcf101f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.6-gpl_hc2c16d8_100.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-5_h4a7cf45_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-5_h0358290_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.19.0-hcf29cc6_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.4-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-5_h47877c9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-2.5.0-hd28c85e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-spdlog-2.5.0-h12fcf84_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.5.0-py311hc5d5c7c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.67.0-had1ee68_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsolv-0.7.35-h9463b59_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.51.0-hb03c661_1.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/libxml2-16-2.15.2-hca6bf5a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.2-he237659_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/linux-64/lz4-c-1.10.0-h5888daf_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-h280c20c_1002.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/menuinst-2.4.2-py311h38be061_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.1.2-py311hdf67eae_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/ninja-1.13.2-h171cf75_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.2-py311h2e04523_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/patchelf-0.17.2-h58526e2_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pycosat-0.6.6-py311h49ec1c0_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyelftools-0.32-pyh707e725_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.11.0-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.11.15-hd63d673_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py311h3778330_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-14.2.5.post0-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-cpp-14.2.5.post0-h5888daf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/rhash-1.4.6-hb9d3cd8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml-0.18.17-py311haee01d2_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml.clib-0.2.15-py311haee01d2_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-0.11.6-pyh7e86bf3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-9.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools_scm-9.2.2-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/simdjson-4.2.4-hb700be7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/spdlog-1.17.0-hab81395_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/taplo-0.10.0-h2d22210_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.1.0-py311hdf67eae_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_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/linux-64/yaml-cpp-0.8.0-h3f2d84a_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py311haee01d2_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + - pypi: https://files.pythonhosted.org/packages/c5/0d/84a4380f930db0010168e0aa7b7a8fed9ba1835a8fbb1472bc6d0201d529/build-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl + linux-aarch64: + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/auditwheel-6.6.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/backports.zstd-1.3.0-py311h6ce31b0_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-python-1.2.0-py311h14a79a7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/c-ares-1.34.6-he30d5cf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cffi-2.0.0-py311h460c349_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cmake-3.31.8-hc9d863e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/conda-26.1.1-py311hec3470c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cpp-expected-1.3.1-hdc560ac_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/doxygen-1.13.2-h5e0f5ae_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/fmt-12.1.0-h20c602a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/frozendict-2.4.7-py311h19352d5_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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-aarch64/icu-78.2-hcab7f73_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.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/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.0.0-pyhcf101f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/keyutils-1.6.3-h86ecc28_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/krb5-1.22.2-hfd895c2_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.45.1-default_h1979696_101.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libarchive-3.8.6-gpl_hbe7d12b_100.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libblas-3.11.0-5_haddc8a3_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcblas-3.11.0-5_hd72aa62_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcurl-8.19.0-hc57f145_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libedit-3.1.20250104-pl5321h976ea20_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libev-4.33-h31becfc_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.7.4-hfae3067_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-15.2.0-he9431aa_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran-15.2.0-he9431aa_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran5-15.2.0-h1b7bec0_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libiconv-1.18-h90929bb_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblapack-3.11.0-5_h88aeb00_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.2-he30d5cf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmamba-2.5.0-hc712cdd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmamba-spdlog-2.5.0-h3ad78e7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmambapy-2.5.0-py311h6a8bf82_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libnghttp2-1.67.0-ha888d0e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libnsl-2.0.1-h86ecc28_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopenblas-0.3.30-pthreads_h9d3fd7e_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsolv-0.7.36-hdda61c4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.52.0-h10b116e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libssh2-1.11.1-h18c354c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-ng-15.2.0-hdbbeba8_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.41.3-h1022ec0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuv-1.51.0-he30d5cf_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxcrypt-4.4.36-h31becfc_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-16-2.15.2-h79dcc73_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-2.15.2-h825857f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.1-h86ecc28_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lz4-c-1.10.0-h5ad3122_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lzo-2.10-h80f16a2_1002.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/menuinst-2.4.2-py311hec3470c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/msgpack-python-1.1.2-py311hfca10b7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.5-ha32ae93_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ninja-1.13.2-hdc560ac_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/numpy-2.4.2-py311h669026d_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.1-h546c87b_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/patchelf-0.17.2-h884eca8_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pycosat-0.6.6-py311h19352d5_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyelftools-0.32-pyh707e725_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.11.0-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-aarch64/python-3.11.15-h91f4b29_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py311h164a683_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/reproc-14.2.5.post0-h86ecc28_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/reproc-cpp-14.2.5.post0-h5ad3122_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/rhash-1.4.6-h86ecc28_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruamel.yaml-0.18.17-py311h51cfe5d_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruamel.yaml.clib-0.2.15-py311h51cfe5d_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-0.11.6-pyh7e86bf3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-9.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools_scm-9.2.2-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/simdjson-4.2.4-hfefdfc9_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/spdlog-1.17.0-h9f97df7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/taplo-0.10.0-h3618846_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h0dc03b3_103.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ukkonen-1.1.0-py311hfca10b7_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-0.2.5-h80f16a2_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-cpp-0.8.0-h5ad3122_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstandard-0.25.0-py311h51cfe5d_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda + - pypi: https://files.pythonhosted.org/packages/c5/0d/84a4380f930db0010168e0aa7b7a8fed9ba1835a8fbb1472bc6d0201d529/build-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl + publish: + channels: + - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple + options: + pypi-prerelease-mode: if-necessary-or-explicit + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py314h3de4e8d_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py314h4a8dc5f_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.1.1-py314hdafbbf9_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cpp-expected-1.3.1-h171cf75_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-hff5e90c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/frozendict-2.4.7-py314h5bd0f2a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gh-2.88.1-h76a2195_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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-78.3-h33c6efd_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.1.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.6-gpl_hc2c16d8_100.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.19.0-hcf29cc6_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.5-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-2.5.0-hd28c85e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-spdlog-2.5.0-h12fcf84_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.5.0-py314hcbd71af_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsolv-0.7.36-h9463b59_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42-h5347b49_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-16-2.15.2-hca6bf5a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.2-he237659_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-h280c20c_1002.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/menuinst-2.4.2-py314hdafbbf9_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.1.2-py314h9891dd4_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pycosat-0.6.6-py314h5bd0f2a_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.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.14.3-h32b2ec7_101_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py314h67df5f8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-14.2.5.post0-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-cpp-14.2.5.post0-h5888daf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.33.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml-0.18.17-py314h0f05182_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml.clib-0.2.15-py314h0f05182_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/simdjson-4.2.4-hb700be7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/spdlog-1.17.0-hab81395_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/taplo-0.10.0-h2d22210_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.1.0-py314h9891dd4_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_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/linux-64/yaml-cpp-0.8.0-h3f2d84a_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py314h0f05182_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + - pypi: https://files.pythonhosted.org/packages/34/71/1ea5a7352ae516d5512d17babe7e1b87d9db5150b21f794b1377eac1edc0/cryptography-46.0.6-cp311-abi3-manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/42/77/de194443bf38daed9452139e960c632b0ef9f9a5dd9ce605fdf18ca9f1b1/id-1.6.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fd/c4/813bb09f0985cb21e959f21f2464169eca882656849adf727ac7bb7e1767/jaraco_functools-4.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/d6/b7/ec1cbc6b297a808c513f59f501656389623fc09ad6a58c640851289c7854/nh3-0.3.4-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e1/67/921ec3024056483db83953ae8e48079ad62b92db7880013ca77632921dd0/readme_renderer-44.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ff/9a/9afaade874b2fa6c752c36f1548f718b5b83af81ed9b76628329dab81c1b/rfc3986-2.0.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3a/7a/882d99539b19b1490cac5d77c67338d126e4122c8276bf640e411650c830/twine-6.2.0-py3-none-any.whl + linux-aarch64: + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-python-1.2.0-py314h352cb57_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/c-ares-1.34.6-he30d5cf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cffi-2.0.0-py314h0bd77cf_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/conda-26.1.1-py314h28a4750_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cpp-expected-1.3.1-hdc560ac_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/fmt-12.1.0-h20c602a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/frozendict-2.4.7-py314h51f160d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gh-2.88.1-h94b2740_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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-aarch64/icu-78.3-hcab7f73_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.1.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/keyutils-1.6.3-h86ecc28_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/krb5-1.22.2-hfd895c2_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.45.1-default_h1979696_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libarchive-3.8.6-gpl_hbe7d12b_100.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcurl-8.19.0-hc57f145_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libedit-3.1.20250104-pl5321h976ea20_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libev-4.33-h31becfc_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.7.5-hfae3067_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-15.2.0-he9431aa_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libiconv-1.18-h90929bb_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.2-he30d5cf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmamba-2.5.0-hc712cdd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmamba-spdlog-2.5.0-h3ad78e7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmambapy-2.5.0-py314h709e558_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmpdec-4.0.0-he30d5cf_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libnghttp2-1.68.1-hd3077d7_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsolv-0.7.36-hdda61c4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.52.0-h10b116e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libssh2-1.11.1-h18c354c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_18.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.42-h1022ec0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-16-2.15.2-h79dcc73_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-2.15.2-h825857f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lz4-c-1.10.0-h5ad3122_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lzo-2.10-h80f16a2_1002.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/menuinst-2.4.2-py314h28a4750_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/msgpack-python-1.1.2-py314hd7d8586_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.5-ha32ae93_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.1-h546c87b_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pycosat-0.6.6-py314h51f160d_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.3-hb06a95a_101_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py314h807365f_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/reproc-14.2.5.post0-h86ecc28_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/reproc-cpp-14.2.5.post0-h5ad3122_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.33.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruamel.yaml-0.18.17-py314h2e8dab5_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruamel.yaml.clib-0.2.15-py314h2e8dab5_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/simdjson-4.2.4-hfefdfc9_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/spdlog-1.17.0-h9f97df7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/taplo-0.10.0-h3618846_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h0dc03b3_103.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ukkonen-1.1.0-py314hd7d8586_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-0.2.5-h80f16a2_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-cpp-0.8.0-h5ad3122_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstandard-0.25.0-py314h2e8dab5_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda + - pypi: https://files.pythonhosted.org/packages/d4/12/123be7292674abf76b21ac1fc0e1af50661f0e5b8f0ec8285faac18eb99e/cryptography-46.0.6-cp311-abi3-manylinux_2_28_aarch64.whl + - pypi: https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/42/77/de194443bf38daed9452139e960c632b0ef9f9a5dd9ce605fdf18ca9f1b1/id-1.6.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fd/c4/813bb09f0985cb21e959f21f2464169eca882656849adf727ac7bb7e1767/jaraco_functools-4.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2b/60/c9a33361da8cde7c7760f091cd10467bc470634e4eea31c8bb70935b00a4/nh3-0.3.4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl + - pypi: https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e1/67/921ec3024056483db83953ae8e48079ad62b92db7880013ca77632921dd0/readme_renderer-44.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ff/9a/9afaade874b2fa6c752c36f1548f718b5b83af81ed9b76628329dab81c1b/rfc3986-2.0.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3a/7a/882d99539b19b1490cac5d77c67338d126e4122c8276bf640e411650c830/twine-6.2.0-py3-none-any.whl + osx-64: + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/brotli-python-1.2.0-py314h3262eb8_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_9.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.34.6-hb5e19a0_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cffi-2.0.0-py314h8ca4d5a_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/conda-26.1.1-py314hee6578b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/cpp-expected-1.3.1-h0ba0a54_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/fmt-12.1.0-hda137b5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/frozendict-2.4.7-py314h6482030_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/gh-2.88.1-hdaada87_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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-64/icu-78.3-h25d91c4_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.1.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/krb5-1.22.2-h207b36a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libarchive-3.8.6-gpl_h2bf6321_100.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcurl-8.19.0-h8f0b9e4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-22.1.2-h19cb2f5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libedit-3.1.20250104-pl5321ha958ccf_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libev-4.33-h10d778d_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.7.5-hcc62823_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.5.2-hd1f9c09_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.18-h57a12c2_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.2-h11316ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libmamba-2.5.0-h7fe6c55_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libmamba-spdlog-2.5.0-hb923e0c_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libmambapy-2.5.0-py314haca2e77_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libmpdec-4.0.0-hf3981d6_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.68.1-h70048d4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsolv-0.7.36-hf97c9bc_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.52.0-h77d7759_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.11.1-hed3591d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libxml2-16-2.15.2-h7a90416_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.15.2-hd552753_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.2-hbb4bfdb_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/lz4-c-1.10.0-h240833e_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/lzo-2.10-h4132b18_1002.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/menuinst-2.4.2-py314hee6578b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/msgpack-python-1.1.2-py314h00ed6fe_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-h0622a9a_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.6.1-hb6871ef_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/pycosat-0.6.6-py314h03d016b_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.14.3-h4f44bb5_101_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/pyyaml-6.0.3-py314h10d0514_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/reproc-14.2.5.post0-h6e16a3a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/reproc-cpp-14.2.5.post0-h240833e_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.33.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml-0.18.17-py314hd330473_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml.clib-0.2.15-py314hd330473_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/simdjson-4.2.4-hcb651aa_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/spdlog-1.17.0-h30f01e4_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/taplo-0.10.0-hffa81eb_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h7142dee_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ukkonen-1.1.0-py314h473ef84_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/yaml-0.2.5-h4132b18_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/yaml-cpp-0.8.0-h92383a6_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/zstandard-0.25.0-py314hd1e8ddb_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-h3eecb57_6.conda + - pypi: https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/42/77/de194443bf38daed9452139e960c632b0ef9f9a5dd9ce605fdf18ca9f1b1/id-1.6.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fd/c4/813bb09f0985cb21e959f21f2464169eca882656849adf727ac7bb7e1767/jaraco_functools-4.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/4a/57/a97955bc95960cfb1f0517043d60a121f4ba93fde252d4d9ffd3c2a9eead/nh3-0.3.4-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl + - pypi: https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e1/67/921ec3024056483db83953ae8e48079ad62b92db7880013ca77632921dd0/readme_renderer-44.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ff/9a/9afaade874b2fa6c752c36f1548f718b5b83af81ed9b76628329dab81c1b/rfc3986-2.0.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3a/7a/882d99539b19b1490cac5d77c67338d126e4122c8276bf640e411650c830/twine-6.2.0-py3-none-any.whl + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.2.0-py314h3daef5d_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-2.0.0-py314h44086f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/conda-26.1.1-py314h4dc9dd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cpp-expected-1.3.1-h4f10f1e_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/fmt-12.1.0-h403dcb5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/frozendict-2.4.7-py314h0612a62_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/gh-2.88.1-h01237fd_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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-78.3-hef89b57_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.1.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libarchive-3.8.6-gpl_h6fbacd7_100.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.19.0-hd5a2499_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.2-h55c6f16_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.5-hf6b4638_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_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/liblzma-5.8.2-h8088a28_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmamba-2.5.0-h7950639_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmamba-spdlog-2.5.0-h85b9800_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmambapy-2.5.0-py314hf8f60b7_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.68.1-h8f3e76b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsolv-0.7.36-h7d962ec_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.52.0-h1ae2325_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/libxml2-16-2.15.2-h5ef1a60_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-2.15.2-h8d039ee_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lz4-c-1.10.0-h286801f_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lzo-2.10-h925e9cb_1002.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/menuinst-2.4.2-py314h4dc9dd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/msgpack-python-1.1.2-py314h784bc60_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.1-hd24854e_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pycosat-0.6.6-py314hb84d1df_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.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.14.3-h4c637c5_101_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyyaml-6.0.3-py314h6e9b3f0_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/reproc-14.2.5.post0-h5505292_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/reproc-cpp-14.2.5.post0-h286801f_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.33.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruamel.yaml-0.18.17-py314ha14b1ff_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruamel.yaml.clib-0.2.15-py314ha14b1ff_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/simdjson-4.2.4-ha7d2532_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/spdlog-1.17.0-ha0f8610_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/taplo-0.10.0-h2b2570c_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ukkonen-1.1.0-py314h6cfcd04_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_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/osx-arm64/yaml-cpp-0.8.0-ha1acc90_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.25.0-py314h9d33bd4_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda + - pypi: https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/42/77/de194443bf38daed9452139e960c632b0ef9f9a5dd9ce605fdf18ca9f1b1/id-1.6.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fd/c4/813bb09f0985cb21e959f21f2464169eca882656849adf727ac7bb7e1767/jaraco_functools-4.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/4a/57/a97955bc95960cfb1f0517043d60a121f4ba93fde252d4d9ffd3c2a9eead/nh3-0.3.4-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl + - pypi: https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e1/67/921ec3024056483db83953ae8e48079ad62b92db7880013ca77632921dd0/readme_renderer-44.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ff/9a/9afaade874b2fa6c752c36f1548f718b5b83af81ed9b76628329dab81c1b/rfc3986-2.0.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3a/7a/882d99539b19b1490cac5d77c67338d126e4122c8276bf640e411650c830/twine-6.2.0-py3-none-any.whl + win-64: + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/brotli-python-1.2.0-py314he701e3d_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-h4c7d964_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cffi-2.0.0-py314h5a2d7ad_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/conda-26.1.1-py314h86ab7b2_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cpp-expected-1.3.1-h477610d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/fmt-12.1.0-h7f4e812_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/frozendict-2.4.7-py314h5a2d7ad_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/gh-2.88.1-h36e2d1d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.1.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/krb5-1.22.2-h0ea6238_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libarchive-3.8.6-gpl_he24518a_100.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libcurl-8.19.0-h8206538_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.7.5-hac47afa_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.5.2-h3d046cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libiconv-1.18-hc1393d2_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/liblzma-5.8.2-hfd05255_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libmamba-2.5.0-h06825f5_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libmamba-spdlog-2.5.0-h9ae1bf1_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libmambapy-2.5.0-py314h532c739_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libmpdec-4.0.0-hfd05255_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libsolv-0.7.36-h8883371_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.52.0-hf5d6505_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libssh2-1.11.1-h9aa295b_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-16-2.15.2-h692994f_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-2.15.2-h5d26750_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.2-hfd05255_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/lz4-c-1.10.0-h2466b09_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/lzo-2.10-h6a83c73_1002.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/menuinst-2.4.2-py314h13fbf68_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/msgpack-python-1.1.2-py314h909e829_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.1-hf411b9b_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-win_hba80fca_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/pycosat-0.6.6-py314h5a2d7ad_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyh09c184e_7.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.14.3-h4b44e0e_101_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/pyyaml-6.0.3-py314h2359020_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/reproc-14.2.5.post0-h2466b09_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/reproc-cpp-14.2.5.post0-he0c23c2_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.33.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ruamel.yaml-0.18.17-py314hc5dbbe4_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ruamel.yaml.clib-0.2.15-py314hc5dbbe4_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/simdjson-4.2.4-h49e36cd_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/spdlog-1.17.0-h9f585f1_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/taplo-0.10.0-h63977a8_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h6ed50ae_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyha7b4d00_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ukkonen-1.1.0-py314h909e829_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vc-14.3-h41ae7f8_34.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.44.35208-h818238b_34.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vcomp14-14.44.35208-h818238b_34.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/win_inet_pton-1.1.0-pyh7428d3b_8.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/yaml-0.2.5-h6a83c73_3.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/yaml-cpp-0.8.0-he0c23c2_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/zstandard-0.25.0-py314hc5dbbe4_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.7-h534d264_6.conda + - pypi: https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/42/77/de194443bf38daed9452139e960c632b0ef9f9a5dd9ce605fdf18ca9f1b1/id-1.6.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/fd/c4/813bb09f0985cb21e959f21f2464169eca882656849adf727ac7bb7e1767/jaraco_functools-4.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/73/4f/af8e9071d7464575a7316831938237ffc9d92d27f163dbdd964b1309cd9b/nh3-0.3.4-cp38-abi3-win_amd64.whl + - pypi: https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e1/67/921ec3024056483db83953ae8e48079ad62b92db7880013ca77632921dd0/readme_renderer-44.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ff/9a/9afaade874b2fa6c752c36f1548f718b5b83af81ed9b76628329dab81c1b/rfc3986-2.0.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3a/7a/882d99539b19b1490cac5d77c67338d126e4122c8276bf640e411650c830/twine-6.2.0-py3-none-any.whl + windows-py310: + channels: + - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple + options: + pypi-prerelease-mode: if-necessary-or-explicit + packages: + win-64: + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/backports.zstd-1.3.0-py310h458dff3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/brotli-python-1.2.0-py310hfff998d_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/c-compiler-1.11.0-h528c1b4_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-h4c7d964_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cffi-2.0.0-py310h29418f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cmake-3.31.8-hdcbee5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/conda-26.1.1-py310h5588dad_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cpp-expected-1.3.1-h477610d_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cxx-compiler-1.11.0-h1c1089f_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/doxygen-1.13.2-hbf3f430_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/fmt-12.1.0-h7f4e812_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/frozendict-2.4.7-py310h29418f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/git-2.53.0-h57928b3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.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/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.0.0-pyhcf101f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/krb5-1.22.2-h0ea6238_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libarchive-3.8.6-gpl_he24518a_100.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libblas-3.11.0-5_hf2e6a31_mkl.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libcblas-3.11.0-5_h2a3cdd5_mkl.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libcurl-8.19.0-h8206538_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.7.4-hac47afa_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.5.2-h3d046cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libhwloc-2.12.2-default_h4379cf1_1000.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libiconv-1.18-hc1393d2_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/liblapack-3.11.0-5_hf9ab0e9_mkl.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/liblzma-5.8.2-hfd05255_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libmamba-2.5.0-h06825f5_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libmamba-spdlog-2.5.0-h9ae1bf1_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libmambapy-2.5.0-py310h1916185_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libsolv-0.7.35-h8883371_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.52.0-hf5d6505_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libssh2-1.11.1-h9aa295b_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libuv-1.51.0-hfd05255_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libwinpthread-12.0.0.r4.gg4f2fc60ca-h57928b3_10.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-16-2.15.2-h692994f_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-2.15.2-h5d26750_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/llvm-openmp-22.1.0-h4fa8253_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/lz4-c-1.10.0-h2466b09_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/lzo-2.10-h6a83c73_1002.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/menuinst-2.4.2-py310h73ae2b4_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/mkl-2025.3.0-hac47afa_455.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/msgpack-python-1.1.2-py310he9f1925_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ninja-1.13.2-h477610d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/numpy-2.2.6-py310h4987827_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.1-hf411b9b_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-win_hba80fca_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/pycosat-0.6.6-py310h29418f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.11.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyh09c184e_7.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.10.20-hc20f281_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.10-8_cp310.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/pyyaml-6.0.3-py310hdb0e946_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/reproc-14.2.5.post0-h2466b09_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/reproc-cpp-14.2.5.post0-he0c23c2_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ruamel.yaml-0.18.17-py310h1637853_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ruamel.yaml.clib-0.2.15-py310h1637853_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-0.11.6-pyh7e86bf3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-9.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools_scm-9.2.2-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/simdjson-4.2.4-h49e36cd_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/spdlog-1.17.0-h9f585f1_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/taplo-0.10.0-h63977a8_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/tbb-2022.3.0-h3155e25_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h6ed50ae_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyha7b4d00_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ukkonen-1.1.0-py310he9f1925_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vc-14.3-h41ae7f8_34.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.44.35208-h818238b_34.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vcomp14-14.44.35208-h818238b_34.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vs2022_win-64-19.44.35207-ha74f236_34.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/vswhere-3.1.7-h40126e0_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/win_inet_pton-1.1.0-pyh7428d3b_8.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/yaml-0.2.5-h6a83c73_3.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/yaml-cpp-0.8.0-he0c23c2_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/zstandard-0.25.0-py310h1637853_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.7-h534d264_6.conda + - pypi: https://files.pythonhosted.org/packages/c5/0d/84a4380f930db0010168e0aa7b7a8fed9ba1835a8fbb1472bc6d0201d529/build-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/89/74/bf0ea7b89e114af19a38c2341746fd1f17f1de23fa8d8019cbcd39719c5f/delvewheel-1.12.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/54/16/12b82f791c7f50ddec566873d5bdd245baa1491bac11d15ffb98aecc8f8b/pefile-2024.8.26-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl + windows-py311: + channels: + - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple + options: + pypi-prerelease-mode: if-necessary-or-explicit + packages: + win-64: + - conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/backports.zstd-1.3.0-py311h71c1bcc_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/brotli-python-1.2.0-py311hc5da9e4_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/c-compiler-1.11.0-h528c1b4_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-h4c7d964_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cffi-2.0.0-py311h3485c13_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cmake-3.31.8-hdcbee5b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/conda-26.1.1-py311h1ea47a8_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cpp-expected-1.3.1-h477610d_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/cxx-compiler-1.11.0-h1c1089f_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/doxygen-1.13.2-hbf3f430_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/fmt-12.1.0-h7f4e812_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/frozendict-2.4.7-py311h3485c13_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/git-2.53.0-h57928b3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_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/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.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/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.0.0-pyhcf101f3_3.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/krb5-1.22.2-h0ea6238_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libarchive-3.8.6-gpl_he24518a_100.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libblas-3.11.0-5_hf2e6a31_mkl.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libcblas-3.11.0-5_h2a3cdd5_mkl.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libcurl-8.19.0-h8206538_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.7.4-hac47afa_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.5.2-h3d046cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libhwloc-2.12.2-default_h4379cf1_1000.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libiconv-1.18-hc1393d2_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/liblapack-3.11.0-5_hf9ab0e9_mkl.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/liblzma-5.8.2-hfd05255_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libmamba-2.5.0-h06825f5_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libmamba-spdlog-2.5.0-h9ae1bf1_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libmambapy-2.5.0-py311hb0041a4_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libsolv-0.7.35-h8883371_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.52.0-hf5d6505_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libssh2-1.11.1-h9aa295b_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libuv-1.51.0-hfd05255_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libwinpthread-12.0.0.r4.gg4f2fc60ca-h57928b3_10.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-16-2.15.2-h692994f_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-2.15.2-h5d26750_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/llvm-openmp-22.1.0-h4fa8253_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/lz4-c-1.10.0-h2466b09_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/lzo-2.10-h6a83c73_1002.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/menuinst-2.4.2-py311h3e6a449_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/mkl-2025.3.0-hac47afa_455.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/msgpack-python-1.1.2-py311h3fd045d_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ninja-1.13.2-h477610d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/numpy-2.4.2-py311h80b3fa1_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.1-hf411b9b_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-win_hba80fca_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/pycosat-0.6.6-py311h3485c13_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.11.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyh09c184e_7.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.11.15-h0159041_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/pyyaml-6.0.3-py311h3f79411_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/reproc-14.2.5.post0-h2466b09_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/reproc-cpp-14.2.5.post0-he0c23c2_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ruamel.yaml-0.18.17-py311hf893f09_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ruamel.yaml.clib-0.2.15-py311hf893f09_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-0.11.6-pyh7e86bf3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-9.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools_scm-9.2.2-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/simdjson-4.2.4-h49e36cd_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/spdlog-1.17.0-h9f585f1_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/taplo-0.10.0-h63977a8_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/tbb-2022.3.0-h3155e25_2.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h6ed50ae_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyha7b4d00_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/ukkonen-1.1.0-py311h3fd045d_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vc-14.3-h41ae7f8_34.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.44.35208-h818238b_34.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vcomp14-14.44.35208-h818238b_34.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/vs2022_win-64-19.44.35207-ha74f236_34.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/vswhere-3.1.7-h40126e0_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/win_inet_pton-1.1.0-pyh7428d3b_8.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/yaml-0.2.5-h6a83c73_3.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/yaml-cpp-0.8.0-he0c23c2_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/zstandard-0.25.0-py311hf893f09_1.conda + - conda: https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.7-h534d264_6.conda + - pypi: https://files.pythonhosted.org/packages/c5/0d/84a4380f930db0010168e0aa7b7a8fed9ba1835a8fbb1472bc6d0201d529/build-1.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/89/74/bf0ea7b89e114af19a38c2341746fd1f17f1de23fa8d8019cbcd39719c5f/delvewheel-1.12.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/54/16/12b82f791c7f50ddec566873d5bdd245baa1491bac11d15ffb98aecc8f8b/pefile-2024.8.26-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl +packages: +- conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + build_number: 20 + sha256: 1dd3fffd892081df9726d7eb7e0dea6198962ba775bd88842135a4ddb4deb3c9 + md5: a9f577daf3de00bca7c3c76c0ecbd1de + depends: + - __glibc >=2.17,<3.0.a0 + - libgomp >=7.5.0 + constrains: + - openmp_impl <0.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 28948 + timestamp: 1770939786096 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda + build_number: 20 + sha256: a2527b1d81792a0ccd2c05850960df119c2b6d8f5fdec97f2db7d25dc23b1068 + md5: 468fd3bb9e1f671d36c2cbc677e56f1d + depends: + - libgomp >=7.5.0 + constrains: + - openmp_impl <0.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 28926 + timestamp: 1770939656741 +- conda: https://conda.anaconda.org/conda-forge/osx-64/_openmp_mutex-4.5-7_kmp_llvm.conda + build_number: 7 + sha256: 30006902a9274de8abdad5a9f02ef7c8bb3d69a503486af0c1faee30b023e5b7 + md5: eaac87c21aff3ed21ad9656697bb8326 + depends: + - llvm-openmp >=9.0.1 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 8328 + timestamp: 1764092562779 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/_openmp_mutex-4.5-7_kmp_llvm.conda + build_number: 7 + sha256: 7acaa2e0782cad032bdaf756b536874346ac1375745fb250e9bdd6a48a7ab3cd + md5: a44032f282e7d2acdeb1c240308052dd + depends: + - llvm-openmp >=9.0.1 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 8325 + timestamp: 1764092507920 +- pypi: https://files.pythonhosted.org/packages/a9/ba/000a1996d4308bc65120167c21241a3b205464a2e0b58deda26ae8ac21d1/altgraph-0.17.5-py2.py3-none-any.whl + name: altgraph + version: 0.17.5 + sha256: f3a22400bce1b0c701683820ac4f3b159cd301acab067c51c653e06961600597 +- conda: https://conda.anaconda.org/conda-forge/noarch/archspec-0.2.5-pyhd8ed1ab_0.conda + sha256: eb68e1ce9e9a148168a4b1e257a8feebffdb0664b557bb526a1e4853f2d2fc00 + md5: 845b38297fca2f2d18a29748e2ece7fa + depends: + - python >=3.9 + license: MIT OR Apache-2.0 + purls: + - pkg:pypi/archspec?source=hash-mapping + size: 50894 + timestamp: 1737352715041 +- conda: https://conda.anaconda.org/conda-forge/noarch/auditwheel-6.6.0-pyhd8ed1ab_0.conda + sha256: edba8fbf77c737ee991ae56f3cf5297f23c82eeb6033d6cfb4b78c2545cc66f0 + md5: b0eb66b5e5335471c1148199a26ceb79 + depends: + - packaging >=20.9 + - pyelftools >=0.24 + - python >=3.10 + license: MIT + license_family: MIT + purls: + - pkg:pypi/auditwheel?source=hash-mapping + size: 51557 + timestamp: 1767633848607 +- conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.3.0-py310h69bd2ac_0.conda + sha256: 6660be15a45175c98f750b8bbc3fd07e0da36043624b376de49769bd14a0a16f + md5: 276a3ddf300498921601822e3b407088 + depends: + - python + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - zstd >=1.5.7,<1.6.0a0 + - python_abi 3.10.* *_cp310 + license: BSD-3-Clause AND MIT AND EPL-2.0 + purls: + - pkg:pypi/backports-zstd?source=hash-mapping + size: 191286 + timestamp: 1767044984395 +- conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.3.0-py311h6b1f9c4_0.conda + sha256: 246e50ec7fc222875c6ecfa3feab77f5661dc43e26397bc01d9e0310e3cd48a0 + md5: adda5ef2a74c9bdb338ff8a51192898a + depends: + - python + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - python_abi 3.11.* *_cp311 + - zstd >=1.5.7,<1.6.0a0 + license: BSD-3-Clause AND MIT AND EPL-2.0 + purls: + - pkg:pypi/backports-zstd?source=hash-mapping + size: 244920 + timestamp: 1767044984647 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/backports.zstd-1.3.0-py310hfa1aa29_0.conda + sha256: 92708591d7219370df1b63a96f68be0a2bc6422b8c5c35757b27751ab658ac44 + md5: e6c4c73503900c04b9e8d273fc5db976 + depends: + - python + - python 3.10.* *_cpython + - libgcc >=14 + - python_abi 3.10.* *_cp310 + - zstd >=1.5.7,<1.6.0a0 + license: BSD-3-Clause AND MIT AND EPL-2.0 + purls: + - pkg:pypi/backports-zstd?source=hash-mapping + size: 196369 + timestamp: 1767044996002 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/backports.zstd-1.3.0-py311h6ce31b0_0.conda + sha256: b11baef215becac7d657289bc4171640be7ec6ff5068d3f9fb8a2b0e06242852 + md5: 219e216268cad83c58f10435ce2001fb + depends: + - python + - python 3.11.* *_cpython + - libgcc >=14 + - zstd >=1.5.7,<1.6.0a0 + - python_abi 3.11.* *_cp311 + license: BSD-3-Clause AND MIT AND EPL-2.0 + purls: + - pkg:pypi/backports-zstd?source=hash-mapping + size: 250129 + timestamp: 1767044999147 +- conda: https://conda.anaconda.org/conda-forge/noarch/backports.zstd-1.3.0-py314h680f03e_0.conda + noarch: generic + sha256: c31ab719d256bc6f89926131e88ecd0f0c5d003fe8481852c6424f4ec6c7eb29 + md5: a2ac7763a9ac75055b68f325d3255265 + depends: + - python >=3.14 + license: BSD-3-Clause AND MIT AND EPL-2.0 + purls: [] + size: 7514 + timestamp: 1767044983590 +- conda: https://conda.anaconda.org/conda-forge/win-64/backports.zstd-1.3.0-py310h458dff3_0.conda + sha256: ceb8b49b9bf0246b606089ce95e5afe0c4fd39ada3c8c381a3d03fd9beafba88 + md5: 9f9e5cd3aa06ea10681a65355f5dca09 + depends: + - python + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - python_abi 3.10.* *_cp310 + - zstd >=1.5.7,<1.6.0a0 + license: BSD-3-Clause AND MIT AND EPL-2.0 + purls: + - pkg:pypi/backports-zstd?source=hash-mapping + size: 190164 + timestamp: 1767045016166 +- conda: https://conda.anaconda.org/conda-forge/win-64/backports.zstd-1.3.0-py311h71c1bcc_0.conda + sha256: 5a30429e009b93c6dffe539cf0e3d220ef8d36ea42d36ca5c26b603cb3319c71 + md5: 49eb28c4f92e8a7440e3da6d8e8b5e58 + depends: + - python + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - zstd >=1.5.7,<1.6.0a0 + - python_abi 3.11.* *_cp311 + license: BSD-3-Clause AND MIT AND EPL-2.0 + purls: + - pkg:pypi/backports-zstd?source=hash-mapping + size: 243289 + timestamp: 1767045012846 +- conda: https://conda.anaconda.org/conda-forge/linux-64/binutils-2.45.1-default_h4852527_101.conda + sha256: 2851d34944b056d028543f0440fb631aeeff204151ea09589d8d9c13882395de + md5: 9902aeb08445c03fb31e01beeb173988 + depends: + - binutils_impl_linux-64 >=2.45.1,<2.45.2.0a0 + license: GPL-3.0-only + license_family: GPL + purls: [] + size: 35128 + timestamp: 1770267175160 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/binutils-2.45.1-default_hf1166c9_101.conda + sha256: 7113440420c6f31742c2b29d7590900362007a0bb0d31f9bc5c9a1379d9ab702 + md5: 77f58300ab7d95ce79f9c2c13ad72d5c + depends: + - binutils_impl_linux-aarch64 >=2.45.1,<2.45.2.0a0 + license: GPL-3.0-only + license_family: GPL + purls: [] + size: 35322 + timestamp: 1770267247190 +- conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_impl_linux-64-2.45.1-default_hfdba357_101.conda + sha256: 74341b26a2b9475dc14ba3cf12432fcd10a23af285101883e720216d81d44676 + md5: 83aa53cb3f5fc849851a84d777a60551 + depends: + - ld_impl_linux-64 2.45.1 default_hbd61a6d_101 + - sysroot_linux-64 + - zstd >=1.5.7,<1.6.0a0 + license: GPL-3.0-only + license_family: GPL + purls: [] + size: 3744895 + timestamp: 1770267152681 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/binutils_impl_linux-aarch64-2.45.1-default_h5f4c503_101.conda + sha256: e90ab42a5225dc1eaa6e4e7201cd7b8ed52dad6ec46814be7e5a4039433ae85c + md5: df6e1dc38cbe5642350fa09d4a1d546b + depends: + - ld_impl_linux-aarch64 2.45.1 default_h1979696_101 + - sysroot_linux-aarch64 + - zstd >=1.5.7,<1.6.0a0 + license: GPL-3.0-only + license_family: GPL + purls: [] + size: 4741684 + timestamp: 1770267224406 +- conda: https://conda.anaconda.org/conda-forge/linux-64/binutils_linux-64-2.45.1-default_h4852527_101.conda + sha256: 4826f97d33cbe54459970a1e84500dbe0cccf8326aaf370e707372ae20ec5a47 + md5: dec96579f9a7035a59492bf6ee613b53 + depends: + - binutils_impl_linux-64 2.45.1 default_hfdba357_101 + license: GPL-3.0-only + license_family: GPL + purls: [] + size: 36060 + timestamp: 1770267177798 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/binutils_linux-aarch64-2.45.1-default_hf1166c9_101.conda + sha256: 4ed3cf8af327b1c8b7e71433c98eb0154027e07b726136e81235276e9025489a + md5: 99924e610d9960dc3d8b865614787cec + depends: + - binutils_impl_linux-aarch64 2.45.1 default_h5f4c503_101 + license: GPL-3.0-only + license_family: GPL + purls: [] + size: 36223 + timestamp: 1770267249899 +- conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda + sha256: ea5f4c876eff2ed469551b57f1cc889a3c01128bf3e2e10b1fea11c3ef39eac2 + md5: c7eb87af73750d6fd97eff8bbee8cb9c + depends: + - python >=3.9 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/boltons?source=hash-mapping + size: 302296 + timestamp: 1749686302834 +- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py310hba01987_1.conda + sha256: f036fe554d902549f86689a9650a0996901d5c9242b0a1e3fbfe6dbccd2ae011 + md5: 393fca4557fbd2c4d995dcb89f569048 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + constrains: + - libbrotlicommon 1.2.0 hb03c661_1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/brotli?source=hash-mapping + size: 367099 + timestamp: 1764017439384 +- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py311h66f275b_1.conda + sha256: c36eb061d9ead85f97644cfb740d485dba9b8823357f35c17851078e95e975c1 + md5: 86daecb8e4ed1042d5dc6efbe0152590 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + constrains: + - libbrotlicommon 1.2.0 hb03c661_1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/brotli?source=hash-mapping + size: 367573 + timestamp: 1764017405384 +- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py314h3de4e8d_1.conda + sha256: 3ad3500bff54a781c29f16ce1b288b36606e2189d0b0ef2f67036554f47f12b0 + md5: 8910d2c46f7e7b519129f486e0fe927a + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + constrains: + - libbrotlicommon 1.2.0 hb03c661_1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/brotli?source=hash-mapping + size: 367376 + timestamp: 1764017265553 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-python-1.2.0-py310hbe54bbb_1.conda + sha256: febea9d5c157f0a78dc0ffde32fe37b1f19eae812784f6e5505d471bf60d6f43 + md5: 49a57b1956565528e382d8c9af4854c7 + depends: + - libgcc >=14 + - libstdcxx >=14 + - python >=3.10,<3.11.0a0 + - python >=3.10,<3.11.0a0 *_cpython + - python_abi 3.10.* *_cp310 + constrains: + - libbrotlicommon 1.2.0 he30d5cf_1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/brotli?source=hash-mapping + size: 372450 + timestamp: 1764017428950 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-python-1.2.0-py311h14a79a7_1.conda + sha256: bf73f124e8dd683c5f414b9bea077246fcdec3f6c530bd83234b5eb329b52423 + md5: 292e7c014bfab5c77a2ff9c92728bb50 + depends: + - libgcc >=14 + - libstdcxx >=14 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + constrains: + - libbrotlicommon 1.2.0 he30d5cf_1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/brotli?source=hash-mapping + size: 373346 + timestamp: 1764017600174 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/brotli-python-1.2.0-py314h352cb57_1.conda + sha256: 5a5b0cdcd7ed89c6a8fb830924967f6314a2b71944bc1ebc2c105781ba97aa75 + md5: a1b5c571a0923a205d663d8678df4792 + depends: + - libgcc >=14 + - libstdcxx >=14 + - python >=3.14,<3.15.0a0 + - python >=3.14,<3.15.0a0 *_cp314 + - python_abi 3.14.* *_cp314 + constrains: + - libbrotlicommon 1.2.0 he30d5cf_1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/brotli?source=hash-mapping + size: 373193 + timestamp: 1764017486851 +- conda: https://conda.anaconda.org/conda-forge/osx-64/brotli-python-1.1.0-py310h9e9d8ca_1.conda + sha256: 57d66ca3e072b889c94cfaf56eb7e1794d3b1b3179bd475a4edef50a03359354 + md5: 2362e323293e7699cf1e621d502f86d6 + depends: + - libcxx >=15.0.7 + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + constrains: + - libbrotlicommon 1.1.0 h0dc2134_1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/brotli?source=hash-mapping + size: 367037 + timestamp: 1695990378635 +- conda: https://conda.anaconda.org/conda-forge/osx-64/brotli-python-1.1.0-py311hdf8f085_1.conda + sha256: 0f5e0a7de58006f349220365e32db521a1fe494c37ee455e5ecf05b8fe567dcc + md5: 546fdccabb90492fbaf2da4ffb78f352 + depends: + - libcxx >=15.0.7 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + constrains: + - libbrotlicommon 1.1.0 h0dc2134_1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/brotli?source=hash-mapping + size: 366864 + timestamp: 1695990449997 +- conda: https://conda.anaconda.org/conda-forge/osx-64/brotli-python-1.2.0-py314h3262eb8_1.conda + sha256: 2e34922abda4ac5726c547887161327b97c3bbd39f1204a5db162526b8b04300 + md5: 389d75a294091e0d7fa5a6fc683c4d50 + depends: + - __osx >=10.13 + - libcxx >=19 + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + constrains: + - libbrotlicommon 1.2.0 h8616949_1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/brotli?source=hash-mapping + size: 390153 + timestamp: 1764017784596 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.1.0-py310h1253130_1.conda + sha256: dab21e18c0275bfd93a09b751096998485677ed17c2e2d08298bc5b43c10bee1 + md5: 26fab7f65a80fff9f402ec3b7860b88a + depends: + - libcxx >=15.0.7 + - python >=3.10,<3.11.0a0 + - python >=3.10,<3.11.0a0 *_cpython + - python_abi 3.10.* *_cp310 + constrains: + - libbrotlicommon 1.1.0 hb547adb_1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/brotli?source=hash-mapping + size: 344275 + timestamp: 1695990848681 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.1.0-py311ha891d26_1.conda + sha256: 2d78c79ccf2c17236c52ef217a4c34b762eb7908a6903d94439f787aac1c8f4b + md5: 5e802b015e33447d1283d599d21f052b + depends: + - libcxx >=15.0.7 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + constrains: + - libbrotlicommon 1.1.0 hb547adb_1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/brotli?source=hash-mapping + size: 343332 + timestamp: 1695991223439 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.2.0-py314h3daef5d_1.conda + sha256: 5c2e471fd262fcc3c5a9d5ea4dae5917b885e0e9b02763dbd0f0d9635ed4cb99 + md5: f9501812fe7c66b6548c7fcaa1c1f252 + depends: + - __osx >=11.0 + - libcxx >=19 + - python >=3.14,<3.15.0a0 + - python >=3.14,<3.15.0a0 *_cp314 + - python_abi 3.14.* *_cp314 + constrains: + - libbrotlicommon 1.2.0 hc919400_1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/brotli?source=hash-mapping + size: 359854 + timestamp: 1764018178608 +- conda: https://conda.anaconda.org/conda-forge/win-64/brotli-python-1.2.0-py310hfff998d_1.conda + sha256: fd250a4f92c2176f23dd4e07de1faf76741dabcc8fa00b182748db4d9578ff7e + md5: 0caf12fa6690b7f64883b2239853dda0 + depends: + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + constrains: + - libbrotlicommon 1.2.0 hfd05255_1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/brotli?source=hash-mapping + size: 335476 + timestamp: 1764018212429 +- conda: https://conda.anaconda.org/conda-forge/win-64/brotli-python-1.2.0-py311hc5da9e4_1.conda + sha256: 1803c838946d79ef6485ae8c7dafc93e28722c5999b059a34118ef758387a4c9 + md5: b0c459f98ac5ea504a9d9df6242f7ee1 + depends: + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + constrains: + - libbrotlicommon 1.2.0 hfd05255_1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/brotli?source=hash-mapping + size: 335333 + timestamp: 1764018370925 +- conda: https://conda.anaconda.org/conda-forge/win-64/brotli-python-1.2.0-py314he701e3d_1.conda + sha256: 6854ee7675135c57c73a04849c29cbebc2fb6a3a3bfee1f308e64bf23074719b + md5: 1302b74b93c44791403cbeee6a0f62a3 + depends: + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + constrains: + - libbrotlicommon 1.2.0 hfd05255_1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/brotli?source=hash-mapping + size: 335782 + timestamp: 1764018443683 +- pypi: https://files.pythonhosted.org/packages/c5/0d/84a4380f930db0010168e0aa7b7a8fed9ba1835a8fbb1472bc6d0201d529/build-1.4.0-py3-none-any.whl + name: build + version: 1.4.0 + sha256: 6a07c1b8eb6f2b311b96fcbdbce5dab5fe637ffda0fd83c9cac622e927501596 + requires_dist: + - packaging>=24.0 + - pyproject-hooks + - colorama ; os_name == 'nt' + - importlib-metadata>=4.6 ; python_full_version < '3.10.2' + - tomli>=1.1.0 ; python_full_version < '3.11' + - uv>=0.1.18 ; extra == 'uv' + - virtualenv>=20.11 ; python_full_version < '3.10' and extra == 'virtualenv' + - virtualenv>=20.17 ; python_full_version >= '3.10' and python_full_version < '3.14' and extra == 'virtualenv' + - virtualenv>=20.31 ; python_full_version >= '3.14' and extra == 'virtualenv' + requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda + sha256: 0b75d45f0bba3e95dc693336fa51f40ea28c980131fec438afb7ce6118ed05f6 + md5: d2ffd7602c02f2b316fd921d39876885 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: bzip2-1.0.6 + license_family: BSD + purls: [] + size: 260182 + timestamp: 1771350215188 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda + sha256: b3495077889dde6bb370938e7db82be545c73e8589696ad0843a32221520ad4c + md5: 840d8fc0d7b3209be93080bc20e07f2d + depends: + - libgcc >=14 + license: bzip2-1.0.6 + license_family: BSD + purls: [] + size: 192412 + timestamp: 1771350241232 +- conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h10d778d_5.conda + sha256: 61fb2b488928a54d9472113e1280b468a309561caa54f33825a3593da390b242 + md5: 6097a6ca9ada32699b5fc4312dd6ef18 + license: bzip2-1.0.6 + license_family: BSD + purls: [] + size: 127885 + timestamp: 1699280178474 +- conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_9.conda + sha256: 9f242f13537ef1ce195f93f0cc162965d6cc79da578568d6d8e50f70dd025c42 + md5: 4173ac3b19ec0a4f400b4f782910368b + depends: + - __osx >=10.13 + license: bzip2-1.0.6 + license_family: BSD + purls: [] + size: 133427 + timestamp: 1771350680709 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h93a5062_5.conda + sha256: bfa84296a638bea78a8bb29abc493ee95f2a0218775642474a840411b950fe5f + md5: 1bbc659ca658bfd49a481b5ef7a0f40f + license: bzip2-1.0.6 + license_family: BSD + purls: [] + size: 122325 + timestamp: 1699280294368 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda + sha256: 540fe54be35fac0c17feefbdc3e29725cce05d7367ffedfaaa1bdda234b019df + md5: 620b85a3f45526a8bc4d23fd78fc22f0 + depends: + - __osx >=11.0 + license: bzip2-1.0.6 + license_family: BSD + purls: [] + size: 124834 + timestamp: 1771350416561 +- conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda + sha256: 76dfb71df5e8d1c4eded2dbb5ba15bb8fb2e2b0fe42d94145d5eed4c75c35902 + md5: 4cb8e6b48f67de0b018719cdf1136306 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: bzip2-1.0.6 + license_family: BSD + purls: [] + size: 56115 + timestamp: 1771350256444 +- conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda + sha256: cc9accf72fa028d31c2a038460787751127317dcfa991f8d1f1babf216bb454e + md5: 920bb03579f15389b9e512095ad995b7 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: MIT + license_family: MIT + purls: [] + size: 207882 + timestamp: 1765214722852 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/c-ares-1.34.6-he30d5cf_0.conda + sha256: 7ec8a68efe479e2e298558cbc2e79d29430d5c7508254268818c0ae19b206519 + md5: 1dfbec0d08f112103405756181304c16 + depends: + - libgcc >=14 + license: MIT + license_family: MIT + purls: [] + size: 217215 + timestamp: 1765214743735 +- conda: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.28.1-h10d778d_0.conda + sha256: fccd7ad7e3dfa6b19352705b33eb738c4c55f79f398e106e6cf03bab9415595a + md5: d5eb7992227254c0e9a0ce71151f0079 + license: MIT + license_family: MIT + purls: [] + size: 152607 + timestamp: 1711819681694 +- conda: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.34.6-hb5e19a0_0.conda + sha256: 2f5bc0292d595399df0d168355b4e9820affc8036792d6984bd751fdda2bcaea + md5: fc9a153c57c9f070bebaa7eef30a8f17 + depends: + - __osx >=10.13 + license: MIT + license_family: MIT + purls: [] + size: 186122 + timestamp: 1765215100384 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.28.1-h93a5062_0.conda + sha256: 2fc553d7a75e912efbdd6b82cd7916cc9cb2773e6cd873b77e02d631dd7be698 + md5: 04f776a6139f7eafc2f38668570eb7db + license: MIT + license_family: MIT + purls: [] + size: 150488 + timestamp: 1711819630164 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda + sha256: 2995f2aed4e53725e5efbc28199b46bf311c3cab2648fc4f10c2227d6d5fa196 + md5: bcb3cba70cf1eec964a03b4ba7775f01 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 180327 + timestamp: 1765215064054 +- conda: https://conda.anaconda.org/conda-forge/linux-64/c-compiler-1.11.0-h4d9bdce_0.conda + sha256: 8e7a40f16400d7839c82581410aa05c1f8324a693c9d50079f8c50dc9fb241f0 + md5: abd85120de1187b0d1ec305c2173c71b + depends: + - binutils + - gcc + - gcc_linux-64 14.* + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 6693 + timestamp: 1753098721814 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/c-compiler-1.11.0-hdceaead_0.conda + sha256: a16c5078619d60e54f75336ed2bbb4ee0fb6f711de02dd364983748beda31e04 + md5: 89bc32110bba0dc160bb69427e196dc4 + depends: + - binutils + - gcc + - gcc_linux-aarch64 14.* + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 6721 + timestamp: 1753098688332 +- conda: https://conda.anaconda.org/conda-forge/osx-64/c-compiler-1.10.0-h09a7c41_0.conda + sha256: 6a3f6b72bf5ad154630f79bd600f6ccf0f5c6a4be5297e4831d63016f4220e62 + md5: 7b7c12e4774b83c18612c78073d12adc + depends: + - cctools >=949.0.1 + - clang_osx-64 18.* + - ld64 >=530 + - llvm-openmp + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 6773 + timestamp: 1751115657381 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-compiler-1.10.0-hdf49b6b_0.conda + sha256: efc71f2ae5901bea633c67468b3aa774b6bcf46c9433e1ab5d640e3faf1680b9 + md5: 7ca1bdcc45db75f54ed7b3ac969ed888 + depends: + - cctools >=949.0.1 + - clang_osx-arm64 18.* + - ld64 >=530 + - llvm-openmp + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 6758 + timestamp: 1751115540465 +- conda: https://conda.anaconda.org/conda-forge/win-64/c-compiler-1.11.0-h528c1b4_0.conda + sha256: 55e04bd4af61500cb8cae064386be57d18fbfdf676655ff1c97c7e5d146c6e34 + md5: 6d994ff9ab924ba11c2c07e93afbe485 + depends: + - vs2022_win-64 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 6938 + timestamp: 1753098808371 +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-h4c7d964_0.conda + sha256: 37950019c59b99585cee5d30dbc2cc9696ed4e11f5742606a4db1621ed8f94d6 + md5: f001e6e220355b7f87403a4d0e5bf1ca + depends: + - __win + license: ISC + purls: [] + size: 147734 + timestamp: 1772006322223 +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda + sha256: 67cc7101b36421c5913a1687ef1b99f85b5d6868da3abbf6ec1a4181e79782fc + md5: 4492fd26db29495f0ba23f146cd5638d + depends: + - __unix + license: ISC + purls: [] + size: 147413 + timestamp: 1772006283803 +- conda: https://conda.anaconda.org/conda-forge/osx-64/cctools-986-hd3558d4_0.conda + sha256: 0879b6169986404d3e79e16676fe3de0cd962b522b7e8ef0fdad345400a28571 + md5: 64cd107846d3407b8d75899078ffb2ab + depends: + - cctools_osx-64 986 h58a35ae_0 + - ld64 711 h4e51db5_0 + - libllvm18 >=18.1.1,<18.2.0a0 + license: APSL-2.0 + license_family: Other + purls: [] + size: 21451 + timestamp: 1710484533466 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cctools-986-h4c9edd9_0.conda + sha256: bfbfc99da17828d007286f40af86b44315769cfbcc4beba62a8ae64264bd1193 + md5: abcfabe468c14e506fceab2e85380b3b + depends: + - cctools_osx-arm64 986 hd11630f_0 + - ld64 711 h4c6efb1_0 + - libllvm18 >=18.1.1,<18.2.0a0 + license: APSL-2.0 + license_family: Other + purls: [] + size: 21460 + timestamp: 1710484691219 +- conda: https://conda.anaconda.org/conda-forge/osx-64/cctools_osx-64-986-h58a35ae_0.conda + sha256: a11f85e26b7189af87aa7e42b29a80f6bae73a92710cd5a40e278d6376a66ef5 + md5: 1139258589f2d752a578ed5b2680eb60 + depends: + - ld64_osx-64 >=711,<712.0a0 + - libcxx + - libllvm18 >=18.1.1,<18.2.0a0 + - libzlib >=1.2.13,<2.0.0a0 + - sigtool + constrains: + - ld64 711.* + - cctools 986.* + - clang 18.1.* + license: APSL-2.0 + license_family: Other + purls: [] + size: 1104790 + timestamp: 1710484461097 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cctools_osx-arm64-986-hd11630f_0.conda + sha256: 4152323bbb78e2730fea9004333c9c51fb82a9ddd935f005280bf621849ec53d + md5: cce200c91b2d291c85e66098fe0d31c2 + depends: + - ld64_osx-arm64 >=711,<712.0a0 + - libcxx + - libllvm18 >=18.1.1,<18.2.0a0 + - libzlib >=1.2.13,<2.0.0a0 + - sigtool + constrains: + - cctools 986.* + - clang 18.1.* + - ld64 711.* + license: APSL-2.0 + license_family: Other + purls: [] + size: 1123368 + timestamp: 1710484635601 +- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda + sha256: a6b118fd1ed6099dc4fc03f9c492b88882a780fadaef4ed4f93dc70757713656 + md5: 765c4d97e877cdbbb88ff33152b86125 + depends: + - python >=3.10 + license: ISC + purls: + - pkg:pypi/certifi?source=compressed-mapping + size: 151445 + timestamp: 1772001170301 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py310he7384ee_1.conda + sha256: bf76ead6d59b70f3e901476a73880ac92011be63b151972d135eec55bbbe6091 + md5: 803e2d778b8dcccdc014127ec5001681 + depends: + - __glibc >=2.17,<3.0.a0 + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - pycparser + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cffi?source=hash-mapping + size: 244766 + timestamp: 1761203011221 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py311h03d9500_1.conda + sha256: 3ad13377356c86d3a945ae30e9b8c8734300925ef81a3cb0a9db0d755afbe7bb + md5: 3912e4373de46adafd8f1e97e4bd166b + depends: + - __glibc >=2.17,<3.0.a0 + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - pycparser + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cffi?source=hash-mapping + size: 303338 + timestamp: 1761202960110 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py314h4a8dc5f_1.conda + sha256: c6339858a0aaf5d939e00d345c98b99e4558f285942b27232ac098ad17ac7f8e + md5: cf45f4278afd6f4e6d03eda0f435d527 + depends: + - __glibc >=2.17,<3.0.a0 + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - pycparser + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cffi?source=hash-mapping + size: 300271 + timestamp: 1761203085220 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cffi-2.0.0-py310h0826a50_1.conda + sha256: 63458040026be843a189e319190a0622486017c92ef251d4dff7ec847f9a8418 + md5: 152a5ba791642d8a81fe02d134ab3839 + depends: + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - pycparser + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cffi?source=hash-mapping + size: 261471 + timestamp: 1761204343202 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cffi-2.0.0-py311h460c349_1.conda + sha256: a0a49dc4fc0d177ba75d797660145d9405f956944af75d0c402d7733c6c71f60 + md5: eef8f2527e60a82df85eba1cc4f9d5e1 + depends: + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - pycparser + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cffi?source=hash-mapping + size: 321642 + timestamp: 1761203947874 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cffi-2.0.0-py314h0bd77cf_1.conda + sha256: 728e55b32bf538e792010308fbe55d26d02903ddc295fbe101167903a123dd6f + md5: f333c475896dbc8b15efd8f7c61154c7 + depends: + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - pycparser + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cffi?source=hash-mapping + size: 318357 + timestamp: 1761203973223 +- conda: https://conda.anaconda.org/conda-forge/osx-64/cffi-1.16.0-py310hdca579f_0.conda + sha256: 37802485964f1a3137ed6ab21ebc08fe9d35e7dc4da39f2b72a814644dd1ac15 + md5: b9e6213f0eb91f40c009ce69139c1869 + depends: + - libffi >=3.4,<4.0a0 + - pycparser + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cffi?source=hash-mapping + size: 229407 + timestamp: 1696002017767 +- conda: https://conda.anaconda.org/conda-forge/osx-64/cffi-1.16.0-py311hc0b63fd_0.conda + sha256: 1f13a5fa7f310fdbd27f5eddceb9e62cfb10012c58a58c923dd6f51fa979748a + md5: 15d07b82223cac96af629e5e747ba27a + depends: + - libffi >=3.4,<4.0a0 + - pycparser + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cffi?source=hash-mapping + size: 289932 + timestamp: 1696002096156 +- conda: https://conda.anaconda.org/conda-forge/osx-64/cffi-2.0.0-py314h8ca4d5a_1.conda + sha256: e2c58cc2451cc96db2a3c8ec34e18889878db1e95cc3e32c85e737e02a7916fb + md5: 71c2caaa13f50fe0ebad0f961aee8073 + depends: + - __osx >=10.13 + - libffi >=3.5.2,<3.6.0a0 + - pycparser + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cffi?source=hash-mapping + size: 293633 + timestamp: 1761203106369 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-1.16.0-py310hdcd7c05_0.conda + sha256: 4edab3f1f855554e10950efe064b75138943812af829a764f9b570d1a7189d15 + md5: 8855823d908004e4d3b4fd4218795ad2 + depends: + - libffi >=3.4,<4.0a0 + - pycparser + - python >=3.10,<3.11.0a0 + - python >=3.10,<3.11.0a0 *_cpython + - python_abi 3.10.* *_cp310 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cffi?source=hash-mapping + size: 232227 + timestamp: 1696002085787 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-1.16.0-py311h4a08483_0.conda + sha256: 9430416328fe2a28e206e703de771817064c8613a79a6a21fe7107f6a783104c + md5: cbdde0484a47b40e6ce2a4e5aaeb48d7 + depends: + - libffi >=3.4,<4.0a0 + - pycparser + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cffi?source=hash-mapping + size: 292511 + timestamp: 1696002194472 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-2.0.0-py314h44086f9_1.conda + sha256: 5b5ee5de01eb4e4fd2576add5ec9edfc654fbaf9293e7b7ad2f893a67780aa98 + md5: 10dd19e4c797b8f8bdb1ec1fbb6821d7 + depends: + - __osx >=11.0 + - libffi >=3.5.2,<3.6.0a0 + - pycparser + - python >=3.14,<3.15.0a0 + - python >=3.14,<3.15.0a0 *_cp314 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cffi?source=hash-mapping + size: 292983 + timestamp: 1761203354051 +- conda: https://conda.anaconda.org/conda-forge/win-64/cffi-2.0.0-py310h29418f3_1.conda + sha256: abd04b75ee9a04a2f00dc102b4dc126f393fde58536ca4eaf1a72bb7d60dadf4 + md5: 269ba3d69bf6569296a29425a26400df + depends: + - pycparser + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cffi?source=hash-mapping + size: 239862 + timestamp: 1761203282977 +- conda: https://conda.anaconda.org/conda-forge/win-64/cffi-2.0.0-py311h3485c13_1.conda + sha256: c9caca6098e3d92b1a269159b759d757518f2c477fbbb5949cb9fee28807c1f1 + md5: f02335db0282d5077df5bc84684f7ff9 + depends: + - pycparser + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cffi?source=hash-mapping + size: 297941 + timestamp: 1761203850323 +- conda: https://conda.anaconda.org/conda-forge/win-64/cffi-2.0.0-py314h5a2d7ad_1.conda + sha256: 924f2f01fa7a62401145ef35ab6fc95f323b7418b2644a87fea0ea68048880ed + md5: c360170be1c9183654a240aadbedad94 + depends: + - pycparser + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cffi?source=hash-mapping + size: 294731 + timestamp: 1761203441365 +- conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + sha256: aa589352e61bb221351a79e5946d56916e3c595783994884accdb3b97fe9d449 + md5: 381bd45fb7aa032691f3063aff47e3a1 + depends: + - python >=3.10 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cfgv?source=hash-mapping + size: 13589 + timestamp: 1763607964133 +- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.5-pyhd8ed1ab_0.conda + sha256: 05ea76a016c77839b64f9f8ec581775f6c8a259044bd5b45a177e46ab4e7feac + md5: beb628209b2b354b98203066f90b3287 + depends: + - python >=3.10 + license: MIT + license_family: MIT + purls: + - pkg:pypi/charset-normalizer?source=compressed-mapping + size: 53210 + timestamp: 1772816516728 +- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.6-pyhd8ed1ab_0.conda + sha256: d86dfd428b2e3c364fa90e07437c8405d635aa4ef54b25ab51d9c712be4112a5 + md5: 49ee13eb9b8f44d63879c69b8a40a74b + depends: + - python >=3.10 + license: MIT + license_family: MIT + purls: + - pkg:pypi/charset-normalizer?source=compressed-mapping + size: 58510 + timestamp: 1773660086450 +- conda: https://conda.anaconda.org/conda-forge/osx-64/clang-18.1.3-default_h7151d67_0.conda + sha256: 12fbd85852e6a55612d33e8beb4bfe19b6b9b64b44e97753f5c8a2a42decb64a + md5: 1160f27e680531f1ef4f32517238a7f5 + depends: + - clang-18 18.1.3 default_h7151d67_0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 22898 + timestamp: 1712569254288 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-18.1.3-default_h4cf2255_0.conda + sha256: 613f4c4773f1dd274d2682a9170d52cb466f437a47ebcad2c2634c3b37aeb73f + md5: efbaa3d968b1dcacba9eb980d1ab66f4 + depends: + - clang-18 18.1.3 default_he012953_0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 22913 + timestamp: 1712569692457 +- conda: https://conda.anaconda.org/conda-forge/osx-64/clang-18-18.1.3-default_h7151d67_0.conda + sha256: 41a929a017ef2b1b3c5066ddde16c0e68b5fc15a0de49d61cdf414fc13d09336 + md5: 76cf851fa13b7f48939befb147cc78eb + depends: + - libclang-cpp18.1 18.1.3 default_h7151d67_0 + - libcxx >=16.0.6 + - libllvm18 >=18.1.3,<18.2.0a0 + constrains: + - clangxx 18.1.3 + - llvm-tools 18.1.3 + - clang-tools 18.1.3 + - clangdev 18.1.3 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 760437 + timestamp: 1712569132861 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang-18-18.1.3-default_he012953_0.conda + sha256: edb5c1e2ffc7704b0e0bce0f5315eb1aba8fd9710e61bcbdeb40e340720123c6 + md5: 931dd6124b399ae12172f235f5ace407 + depends: + - libclang-cpp18.1 18.1.3 default_he012953_0 + - libcxx >=16.0.6 + - libllvm18 >=18.1.3,<18.2.0a0 + constrains: + - clang-tools 18.1.3 + - clangxx 18.1.3 + - llvm-tools 18.1.3 + - clangdev 18.1.3 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 754206 + timestamp: 1712569562918 +- conda: https://conda.anaconda.org/conda-forge/osx-64/clang_impl_osx-64-18.1.3-hdbcc6ac_11.conda + sha256: cfa641fb177fc1a75c5e2d9f941ad6576f5786a254d5af265e5b548ebaea29d0 + md5: f895cb5eeb844bc8b2dd9147ec07896b + depends: + - cctools_osx-64 + - clang 18.1.3.* + - compiler-rt 18.1.3.* + - ld64_osx-64 + - llvm-tools 18.1.3.* + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 17413 + timestamp: 1712621383914 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang_impl_osx-arm64-18.1.3-hda94301_11.conda + sha256: f00e3930fa341ad5fa87a90f297b385a949bf2ee100a3a2cc2a135629fde6d7e + md5: 90e54a957e833f7cd2412b6d2e1d84fa + depends: + - cctools_osx-arm64 + - clang 18.1.3.* + - compiler-rt 18.1.3.* + - ld64_osx-arm64 + - llvm-tools 18.1.3.* + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 17571 + timestamp: 1712621386541 +- conda: https://conda.anaconda.org/conda-forge/osx-64/clang_osx-64-18.1.3-hb91bd55_11.conda + sha256: 94f9471f5b5b14a229cc44d65c01d383f79de179830b03045fc864f6489550f3 + md5: b0acbcfd68b99fe852942eea93a0f36d + depends: + - clang_impl_osx-64 18.1.3 hdbcc6ac_11 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 20494 + timestamp: 1712621391590 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/clang_osx-arm64-18.1.3-h54d7cd3_11.conda + sha256: 595cbec0f835ba16ad551315079193d16fc7f3a4e136aa1045ab9104cac79bf7 + md5: 7bdafeb8d61d59551df2417995bc3d46 + depends: + - clang_impl_osx-arm64 18.1.3 hda94301_11 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 20490 + timestamp: 1712621394350 +- conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx-18.1.3-default_h7151d67_0.conda + sha256: 53d34a151f47971f55425154423b470273fb2c51e1c0a4ddb261aaa6502a7d50 + md5: 323c1678ff1cf1b8d05981eb2906f45e + depends: + - clang 18.1.3 default_h7151d67_0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 22972 + timestamp: 1712569279378 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx-18.1.3-default_h4cf2255_0.conda + sha256: 1f9c1605d4f74b1d5df7d44676a5a6c53d542fc8c44d94fcc1d4d1977cede661 + md5: fd98656c5b62774633c84c41f42bdd6d + depends: + - clang 18.1.3 default_h4cf2255_0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 22939 + timestamp: 1712569715149 +- conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_impl_osx-64-18.1.3-h5bc21ce_11.conda + sha256: 89fe02a10de21dc553ff79296ef322536b692e50382e248c8625f07dba6176c2 + md5: 1e203622262bd949727467d61e819184 + depends: + - clang_osx-64 18.1.3 hb91bd55_11 + - clangxx 18.1.3.* + - libcxx >=16 + - libllvm18 >=18.1.3,<18.2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 17496 + timestamp: 1712621429065 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx_impl_osx-arm64-18.1.3-h1ba0cb9_11.conda + sha256: 91c6d2a6d9555110d6710d3766eb724dfdeed17b23a7965649523675d2251fce + md5: 5c29e4473f07af49ced6984531048fa4 + depends: + - clang_osx-arm64 18.1.3 h54d7cd3_11 + - clangxx 18.1.3.* + - libcxx >=16 + - libllvm18 >=18.1.3,<18.2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 17636 + timestamp: 1712621421262 +- conda: https://conda.anaconda.org/conda-forge/osx-64/clangxx_osx-64-18.1.3-hb91bd55_11.conda + sha256: fa2acbc8c9575951a523e1f2dc16bd82d22386fbd312dbe05559bed2be94f306 + md5: 5c514320afcbaef94ab371abd3995bfb + depends: + - clang_osx-64 18.1.3 hb91bd55_11 + - clangxx_impl_osx-64 18.1.3 h5bc21ce_11 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 19255 + timestamp: 1712621436405 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/clangxx_osx-arm64-18.1.3-h54d7cd3_11.conda + sha256: c92c008817c2e25409b1328e580798855d082b504b39d8f42b21791da215c9f6 + md5: 3b5c8fe78441bc034aceadfa80dae7cc + depends: + - clang_osx-arm64 18.1.3 h54d7cd3_11 + - clangxx_impl_osx-arm64 18.1.3 h1ba0cb9_11 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 19244 + timestamp: 1712621431069 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cmake-3.31.8-hc85cc9f_0.conda + sha256: 10660ed21b9d591f8306028bd36212467b94f23bc2f78faec76524f6ee592613 + md5: 057e16a12847eea846ecf99710d3591b + depends: + - __glibc >=2.17,<3.0.a0 + - bzip2 >=1.0.8,<2.0a0 + - libcurl >=8.14.1,<9.0a0 + - libexpat >=2.7.1,<3.0a0 + - libgcc >=14 + - liblzma >=5.8.1,<6.0a0 + - libstdcxx >=14 + - 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: 20991288 + timestamp: 1757877168657 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cmake-3.31.8-hc9d863e_0.conda + sha256: 91cbfd13132b7253a6ef001292f5cf59deac38d2cbc86d6c1ad6ebf344cd998c + md5: 855e698fd08794a573cd6104be8da4d0 + depends: + - bzip2 >=1.0.8,<2.0a0 + - libcurl >=8.14.1,<9.0a0 + - libexpat >=2.7.1,<3.0a0 + - libgcc >=14 + - liblzma >=5.8.1,<6.0a0 + - libstdcxx >=14 + - 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: 20216587 + timestamp: 1757877248575 +- conda: https://conda.anaconda.org/conda-forge/osx-64/cmake-3.27.6-hf40c264_0.conda + sha256: 9216698f88b82e99db950f8c372038931c54ea3e0b0b05e2a3ce03ec4b405df7 + md5: 771da6a52aaf0f9d84114d0ed0d0299f + depends: + - bzip2 >=1.0.8,<2.0a0 + - libcurl >=8.3.0,<9.0a0 + - libcxx >=15.0.7 + - libexpat >=2.5.0,<3.0a0 + - libuv >=1.46.0,<2.0a0 + - libzlib >=1.2.13,<2.0.0a0 + - ncurses >=6.4,<7.0a0 + - rhash >=1.4.4,<2.0a0 + - xz >=5.2.6,<6.0a0 + - zstd >=1.5.5,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 16525734 + timestamp: 1695270838345 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmake-3.27.6-h1c59155_0.conda + sha256: 31be31e358e6f6f8818d8f9c9086da4404f8c6fc89d71d55887bed11ce6d463e + md5: 3c0dd04401438fec44cd113247ba2852 + depends: + - bzip2 >=1.0.8,<2.0a0 + - libcurl >=8.3.0,<9.0a0 + - libcxx >=15.0.7 + - libexpat >=2.5.0,<3.0a0 + - libuv >=1.46.0,<2.0a0 + - libzlib >=1.2.13,<2.0.0a0 + - ncurses >=6.4,<7.0a0 + - rhash >=1.4.4,<2.0a0 + - xz >=5.2.6,<6.0a0 + - zstd >=1.5.5,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 16007289 + timestamp: 1695270816826 +- conda: https://conda.anaconda.org/conda-forge/win-64/cmake-3.31.8-hdcbee5b_0.conda + sha256: 074400a63931d8d571b2b2284bc5f105fd578c381847b05d5e3d0b03c3db8f69 + md5: 96afa0e05c4a683b1c3de91b0259b235 + depends: + - bzip2 >=1.0.8,<2.0a0 + - libcurl >=8.14.1,<9.0a0 + - libexpat >=2.7.1,<3.0a0 + - liblzma >=5.8.1,<6.0a0 + - libuv >=1.51.0,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - ucrt >=10.0.20348.0 + - vc14_runtime >=14.44.35208 + - zstd >=1.5.7,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 14669008 + timestamp: 1757878123930 +- 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/osx-64/compiler-rt-18.1.3-ha38d28d_0.conda + sha256: 623f4a180fdb58c5480ea8e724162a57c5955b2f6ecc938a8314bf853dda4b60 + md5: 7a828727c9afa54e7a773e734f628a88 + depends: + - clang 18.1.3.* + - clangxx 18.1.3.* + - compiler-rt_osx-64 18.1.3.* + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + purls: [] + size: 96452 + timestamp: 1712580504480 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/compiler-rt-18.1.3-h3808999_0.conda + sha256: dfada604649fb2cfa6fb3dbd657fccf81cd01e00a7f6f29da24fc40e36cd51fa + md5: 09f614cf0dc4ea2b249c2e522b337730 + depends: + - clang 18.1.3.* + - clangxx 18.1.3.* + - compiler-rt_osx-arm64 18.1.3.* + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + purls: [] + size: 96152 + timestamp: 1712580507858 +- conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-64-18.1.3-ha38d28d_0.conda + sha256: 4084d02399a9176a7a8bdccc530142b429846c166a1a0d65d15a0b7de465e7bb + md5: 678d71ebac649fc7324026e05930bf4c + depends: + - clang 18.1.3.* + - clangxx 18.1.3.* + constrains: + - compiler-rt 18.1.3 + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + purls: [] + size: 10367732 + timestamp: 1712580438913 +- conda: https://conda.anaconda.org/conda-forge/noarch/compiler-rt_osx-arm64-18.1.3-h3808999_0.conda + sha256: 4bbe97d77ae12edd5c0206d014e0473ae8c4fcacbc1e1b21e8e92fd694608301 + md5: 78c11131b59e53aedcf7854956a9347c + depends: + - clang 18.1.3.* + - clangxx 18.1.3.* + constrains: + - compiler-rt 18.1.3 + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + purls: [] + size: 10165573 + timestamp: 1712580450851 +- conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.1.1-py310hff52083_0.conda + sha256: 38b5e5057fe3a69ea82125874f4653cfda2d5ca764a9a0bb8084e1ea3c53a661 + md5: fdd3d2814d732e0d878fc7d4a2289f7f + depends: + - archspec >=0.2.3 + - boltons >=23.0.0 + - charset-normalizer + - conda-libmamba-solver >=25.4.0 + - conda-package-handling >=2.2.0 + - distro >=1.5.0 + - frozendict >=2.4.2 + - jsonpatch >=1.32 + - menuinst >=2 + - packaging >=23.0 + - platformdirs >=3.10.0 + - pluggy >=1.0.0 + - pycosat >=0.6.3 + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + - requests >=2.28.0,<3 + - ruamel.yaml >=0.11.14,<0.19 + - setuptools >=60.0.0 + - tqdm >=4 + - truststore >=0.8.0 + - zstandard >=0.19.0 + constrains: + - conda-env >=2.6 + - conda-content-trust >=0.1.1 + - conda-build >=25.9 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/conda?source=hash-mapping + size: 999473 + timestamp: 1772191385548 +- conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.1.1-py311h38be061_0.conda + sha256: 9cd790637fcab45938ad49753d15b0cfbe847f9f0d4a1b7213d30b6fb412fede + md5: 52f7c28c287da1a28cb9cabda1f5d0cf + depends: + - archspec >=0.2.3 + - boltons >=23.0.0 + - charset-normalizer + - conda-libmamba-solver >=25.4.0 + - conda-package-handling >=2.2.0 + - distro >=1.5.0 + - frozendict >=2.4.2 + - jsonpatch >=1.32 + - menuinst >=2 + - packaging >=23.0 + - platformdirs >=3.10.0 + - pluggy >=1.0.0 + - pycosat >=0.6.3 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - requests >=2.28.0,<3 + - ruamel.yaml >=0.11.14,<0.19 + - setuptools >=60.0.0 + - tqdm >=4 + - truststore >=0.8.0 + - zstandard >=0.19.0 + constrains: + - conda-env >=2.6 + - conda-build >=25.9 + - conda-content-trust >=0.1.1 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/conda?source=compressed-mapping + size: 1286583 + timestamp: 1772191375962 +- conda: https://conda.anaconda.org/conda-forge/linux-64/conda-26.1.1-py314hdafbbf9_0.conda + sha256: 287ebc90f9659755cf626e1dd1d405690bef16e805942b4a3d8008e2376ff8bf + md5: c1c5e3d6e85f5fe5a47789d7a10b140f + depends: + - archspec >=0.2.3 + - boltons >=23.0.0 + - charset-normalizer + - conda-libmamba-solver >=25.4.0 + - conda-package-handling >=2.2.0 + - distro >=1.5.0 + - frozendict >=2.4.2 + - jsonpatch >=1.32 + - menuinst >=2 + - packaging >=23.0 + - platformdirs >=3.10.0 + - pluggy >=1.0.0 + - pycosat >=0.6.3 + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + - requests >=2.28.0,<3 + - ruamel.yaml >=0.11.14,<0.19 + - setuptools >=60.0.0 + - tqdm >=4 + - truststore >=0.8.0 + - zstandard >=0.19.0 + constrains: + - conda-build >=25.9 + - conda-env >=2.6 + - conda-content-trust >=0.1.1 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/conda?source=hash-mapping + size: 1307275 + timestamp: 1772191378974 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/conda-26.1.1-py310h4c7bcd0_0.conda + sha256: 87aed41c4a995f4939816fce5c3555d66ad9551707fc117f3dde3884629c5b3a + md5: 42e348e1bb733f0095fa1ded7e1cfb00 + depends: + - archspec >=0.2.3 + - boltons >=23.0.0 + - charset-normalizer + - conda-libmamba-solver >=25.4.0 + - conda-package-handling >=2.2.0 + - distro >=1.5.0 + - frozendict >=2.4.2 + - jsonpatch >=1.32 + - menuinst >=2 + - packaging >=23.0 + - platformdirs >=3.10.0 + - pluggy >=1.0.0 + - pycosat >=0.6.3 + - python >=3.10,<3.11.0a0 + - python >=3.10,<3.11.0a0 *_cpython + - python_abi 3.10.* *_cp310 + - requests >=2.28.0,<3 + - ruamel.yaml >=0.11.14,<0.19 + - setuptools >=60.0.0 + - tqdm >=4 + - truststore >=0.8.0 + - zstandard >=0.19.0 + constrains: + - conda-env >=2.6 + - conda-content-trust >=0.1.1 + - conda-build >=25.9 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/conda?source=hash-mapping + size: 1001496 + timestamp: 1772191435996 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/conda-26.1.1-py311hec3470c_0.conda + sha256: 6c0920b4eaf5c13201c05c7de3080289468a1281ad9eb14719635815acf44523 + md5: 2d434ed94247068c4cc439c22d51b693 + depends: + - archspec >=0.2.3 + - boltons >=23.0.0 + - charset-normalizer + - conda-libmamba-solver >=25.4.0 + - conda-package-handling >=2.2.0 + - distro >=1.5.0 + - frozendict >=2.4.2 + - jsonpatch >=1.32 + - menuinst >=2 + - packaging >=23.0 + - platformdirs >=3.10.0 + - pluggy >=1.0.0 + - pycosat >=0.6.3 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + - requests >=2.28.0,<3 + - ruamel.yaml >=0.11.14,<0.19 + - setuptools >=60.0.0 + - tqdm >=4 + - truststore >=0.8.0 + - zstandard >=0.19.0 + constrains: + - conda-env >=2.6 + - conda-build >=25.9 + - conda-content-trust >=0.1.1 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/conda?source=hash-mapping + size: 1288665 + timestamp: 1772191444841 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/conda-26.1.1-py314h28a4750_0.conda + sha256: 694fdd47a58ea57163ca5bb64bbe1332d413644f3a2cfa9ea515828aa98b73ab + md5: d511b5ac95faec60409f48c00a6d8f06 + depends: + - archspec >=0.2.3 + - boltons >=23.0.0 + - charset-normalizer + - conda-libmamba-solver >=25.4.0 + - conda-package-handling >=2.2.0 + - distro >=1.5.0 + - frozendict >=2.4.2 + - jsonpatch >=1.32 + - menuinst >=2 + - packaging >=23.0 + - platformdirs >=3.10.0 + - pluggy >=1.0.0 + - pycosat >=0.6.3 + - python >=3.14,<3.15.0a0 + - python >=3.14,<3.15.0a0 *_cp314 + - python_abi 3.14.* *_cp314 + - requests >=2.28.0,<3 + - ruamel.yaml >=0.11.14,<0.19 + - setuptools >=60.0.0 + - tqdm >=4 + - truststore >=0.8.0 + - zstandard >=0.19.0 + constrains: + - conda-build >=25.9 + - conda-content-trust >=0.1.1 + - conda-env >=2.6 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/conda?source=hash-mapping + size: 1311034 + timestamp: 1772191450615 +- conda: https://conda.anaconda.org/conda-forge/osx-64/conda-23.9.0-py310h2ec42d9_2.conda + sha256: 743fb814fa36fc2bfb976d258fc0854ceb6cb2552cf2bc8a6ab7407c8aed0dff + md5: 478a4d7f1b36bbf317b41027e2bc5d9d + depends: + - archspec + - boltons >=23.0.0 + - conda-package-handling >=2.2.0 + - jsonpatch >=1.32 + - packaging >=23.0 + - pluggy >=1.0.0 + - pycosat >=0.6.3 + - pyopenssl >=16.2.0 + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + - requests >=2.27.0,<3 + - ruamel.yaml >=0.11.14,<0.18 + - setuptools >=60.0.0 + - tqdm >=4 + - truststore >=0.8.0 + constrains: + - conda-env >=2.6 + - conda-content-trust >=0.1.1 + - conda-libmamba-solver >=23.7.0 + - conda-build >=3 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/conda?source=hash-mapping + size: 970554 + timestamp: 1698451059802 +- conda: https://conda.anaconda.org/conda-forge/osx-64/conda-23.9.0-py311h6eed73b_2.conda + sha256: 894332c6be0df4be919dadd33dc9bf365e9851db3a6c65b5331986d6277296f4 + md5: 8f27c249b5c0a2185f18250120613565 + depends: + - archspec + - boltons >=23.0.0 + - conda-package-handling >=2.2.0 + - jsonpatch >=1.32 + - packaging >=23.0 + - pluggy >=1.0.0 + - pycosat >=0.6.3 + - pyopenssl >=16.2.0 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - requests >=2.27.0,<3 + - ruamel.yaml >=0.11.14,<0.18 + - setuptools >=60.0.0 + - tqdm >=4 + - truststore >=0.8.0 + constrains: + - conda-libmamba-solver >=23.7.0 + - conda-build >=3 + - conda-env >=2.6 + - conda-content-trust >=0.1.1 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/conda?source=hash-mapping + size: 1264324 + timestamp: 1698451045537 +- conda: https://conda.anaconda.org/conda-forge/osx-64/conda-26.1.1-py314hee6578b_0.conda + sha256: 30f3fda3b376079a273a6a73dc510fdc663c77ba4fa696f82a48545476eb8014 + md5: fa5b5fd3010a1bfcf558901f3ee09b9e + depends: + - archspec >=0.2.3 + - boltons >=23.0.0 + - charset-normalizer + - conda-libmamba-solver >=25.4.0 + - conda-package-handling >=2.2.0 + - distro >=1.5.0 + - frozendict >=2.4.2 + - jsonpatch >=1.32 + - menuinst >=2 + - packaging >=23.0 + - platformdirs >=3.10.0 + - pluggy >=1.0.0 + - pycosat >=0.6.3 + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + - requests >=2.28.0,<3 + - ruamel.yaml >=0.11.14,<0.19 + - setuptools >=60.0.0 + - tqdm >=4 + - truststore >=0.8.0 + - zstandard >=0.19.0 + constrains: + - conda-content-trust >=0.1.1 + - conda-build >=25.9 + - conda-env >=2.6 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/conda?source=hash-mapping + size: 1310551 + timestamp: 1772191748761 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/conda-23.9.0-py310hbe9552e_2.conda + sha256: 58834d003f2dfef45ccd8421adb0bdc4228542223563aa8681f3563c026fb005 + md5: 629fd52fcd8e0559573559a6b008ce0e + depends: + - archspec + - boltons >=23.0.0 + - conda-package-handling >=2.2.0 + - jsonpatch >=1.32 + - packaging >=23.0 + - pluggy >=1.0.0 + - pycosat >=0.6.3 + - pyopenssl >=16.2.0 + - python >=3.10,<3.11.0a0 + - python >=3.10,<3.11.0a0 *_cpython + - python_abi 3.10.* *_cp310 + - requests >=2.27.0,<3 + - ruamel.yaml >=0.11.14,<0.18 + - setuptools >=60.0.0 + - tqdm >=4 + - truststore >=0.8.0 + constrains: + - conda-content-trust >=0.1.1 + - conda-libmamba-solver >=23.7.0 + - conda-env >=2.6 + - conda-build >=3 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/conda?source=hash-mapping + size: 970987 + timestamp: 1698451243924 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/conda-23.9.0-py311h267d04e_2.conda + sha256: 700460cbbf01e9b37b375a62f25e195583964dd87720755d0bad43913c30d928 + md5: f03a4e5f471e82036ebc4b5db54abc9d + depends: + - archspec + - boltons >=23.0.0 + - conda-package-handling >=2.2.0 + - jsonpatch >=1.32 + - packaging >=23.0 + - pluggy >=1.0.0 + - pycosat >=0.6.3 + - pyopenssl >=16.2.0 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + - requests >=2.27.0,<3 + - ruamel.yaml >=0.11.14,<0.18 + - setuptools >=60.0.0 + - tqdm >=4 + - truststore >=0.8.0 + constrains: + - conda-content-trust >=0.1.1 + - conda-env >=2.6 + - conda-libmamba-solver >=23.7.0 + - conda-build >=3 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/conda?source=hash-mapping + size: 1261327 + timestamp: 1698451125796 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/conda-26.1.1-py314h4dc9dd8_0.conda + sha256: e07221f4bda014e492e9a8e99dc5ec307147afd44483346e58eaec6770f10865 + md5: 29a62536271a0869f2d0ecb04e834634 + depends: + - archspec >=0.2.3 + - boltons >=23.0.0 + - charset-normalizer + - conda-libmamba-solver >=25.4.0 + - conda-package-handling >=2.2.0 + - distro >=1.5.0 + - frozendict >=2.4.2 + - jsonpatch >=1.32 + - menuinst >=2 + - packaging >=23.0 + - platformdirs >=3.10.0 + - pluggy >=1.0.0 + - pycosat >=0.6.3 + - python >=3.14,<3.15.0a0 + - python >=3.14,<3.15.0a0 *_cp314 + - python_abi 3.14.* *_cp314 + - requests >=2.28.0,<3 + - ruamel.yaml >=0.11.14,<0.19 + - setuptools >=60.0.0 + - tqdm >=4 + - truststore >=0.8.0 + - zstandard >=0.19.0 + constrains: + - conda-content-trust >=0.1.1 + - conda-build >=25.9 + - conda-env >=2.6 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/conda?source=hash-mapping + size: 1310581 + timestamp: 1772191962239 +- conda: https://conda.anaconda.org/conda-forge/win-64/conda-26.1.1-py310h5588dad_0.conda + sha256: b46279535611a3082d932c0aa5d6e13e2a56bb021a55370879692126a388b8e5 + md5: 1e3fa316ac3da6d31d703ca70c8bbf47 + depends: + - archspec >=0.2.3 + - boltons >=23.0.0 + - charset-normalizer + - conda-libmamba-solver >=25.4.0 + - conda-package-handling >=2.2.0 + - distro >=1.5.0 + - frozendict >=2.4.2 + - jsonpatch >=1.32 + - menuinst >=2 + - packaging >=23.0 + - platformdirs >=3.10.0 + - pluggy >=1.0.0 + - pycosat >=0.6.3 + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + - requests >=2.28.0,<3 + - ruamel.yaml >=0.11.14,<0.19 + - setuptools >=60.0.0 + - tqdm >=4 + - truststore >=0.8.0 + - zstandard >=0.19.0 + constrains: + - conda-content-trust >=0.1.1 + - conda-build >=25.9 + - conda-env >=2.6 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/conda?source=hash-mapping + size: 1002216 + timestamp: 1772191581878 +- conda: https://conda.anaconda.org/conda-forge/win-64/conda-26.1.1-py311h1ea47a8_0.conda + sha256: a2d7a3b3b48bf15bb705a6b6dce061e0ee05275159fbe105acea30be989d13cd + md5: 07554fc0615396c760ca7bebd6a3797c + depends: + - archspec >=0.2.3 + - boltons >=23.0.0 + - charset-normalizer + - conda-libmamba-solver >=25.4.0 + - conda-package-handling >=2.2.0 + - distro >=1.5.0 + - frozendict >=2.4.2 + - jsonpatch >=1.32 + - menuinst >=2 + - packaging >=23.0 + - platformdirs >=3.10.0 + - pluggy >=1.0.0 + - pycosat >=0.6.3 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - requests >=2.28.0,<3 + - ruamel.yaml >=0.11.14,<0.19 + - setuptools >=60.0.0 + - tqdm >=4 + - truststore >=0.8.0 + - zstandard >=0.19.0 + constrains: + - conda-env >=2.6 + - conda-build >=25.9 + - conda-content-trust >=0.1.1 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/conda?source=hash-mapping + size: 1287539 + timestamp: 1772191674230 +- conda: https://conda.anaconda.org/conda-forge/win-64/conda-26.1.1-py314h86ab7b2_0.conda + sha256: 1b6770ef97301830842c57ad0c18ad25858c0d62e2a1b1248d9b37fb1ce3eaf6 + md5: 2ce9348410797986e1c59939d6162826 + depends: + - archspec >=0.2.3 + - boltons >=23.0.0 + - charset-normalizer + - conda-libmamba-solver >=25.4.0 + - conda-package-handling >=2.2.0 + - distro >=1.5.0 + - frozendict >=2.4.2 + - jsonpatch >=1.32 + - menuinst >=2 + - packaging >=23.0 + - platformdirs >=3.10.0 + - pluggy >=1.0.0 + - pycosat >=0.6.3 + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + - requests >=2.28.0,<3 + - ruamel.yaml >=0.11.14,<0.19 + - setuptools >=60.0.0 + - tqdm >=4 + - truststore >=0.8.0 + - zstandard >=0.19.0 + constrains: + - conda-env >=2.6 + - conda-content-trust >=0.1.1 + - conda-build >=25.9 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/conda?source=hash-mapping + size: 1309098 + timestamp: 1772191684896 +- conda: https://conda.anaconda.org/conda-forge/linux-64/conda-gcc-specs-14.3.0-he8ccf15_18.conda + sha256: b90ec0e6a9eb22f7240b3584fe785457cff961fec68d40e6aece5d596f9bbd9a + md5: 0e3e144115c43c9150d18fa20db5f31c + depends: + - gcc_impl_linux-64 >=14.3.0,<14.3.1.0a0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 31705 + timestamp: 1771378159534 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/conda-gcc-specs-14.3.0-hadff5d6_18.conda + sha256: 7b018e74d2f828e887faabc9d5c5bef6d432c3356dcac3e691ee6b24bc82ef52 + md5: 184c1aba41c40e6bc59fa91b37cd7c3f + depends: + - gcc_impl_linux-aarch64 >=14.3.0,<14.3.1.0a0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 31474 + timestamp: 1771377963347 +- conda: https://conda.anaconda.org/conda-forge/noarch/conda-libmamba-solver-25.11.0-pyhd8ed1ab_1.conda + sha256: 001812b000c9791db53a85b0f215952b7497ca1fd6e3070314e20f707556765b + md5: 1d545b8b06123889395de8a3674fc0e7 + depends: + - boltons >=23.0.0 + - libmambapy >=2.0.0 + - msgpack-python >=1.1.1 + - python >=3.10 + - requests >=2.28.0,<3 + - zstandard >=0.15 + constrains: + - conda >=25.9 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/conda-libmamba-solver?source=hash-mapping + size: 56969 + timestamp: 1770137431666 +- conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.4.0-pyh7900ff3_2.conda + sha256: 8b2b1c235b7cbfa8488ad88ff934bdad25bac6a4c035714681fbff85b602f3f0 + md5: 32c158f481b4fd7630c565030f7bc482 + depends: + - conda-package-streaming >=0.9.0 + - python >=3.9 + - requests + - zstandard >=0.15 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/conda-package-handling?source=hash-mapping + size: 257995 + timestamp: 1736345601691 +- conda: https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.12.0-pyhd8ed1ab_0.conda + sha256: 11b76b0be2f629e8035be1d723ccb6e583eb0d2af93bde56113da7fa6e2f2649 + md5: ff75d06af779966a5aeae1be1d409b96 + depends: + - python >=3.9 + - zstandard >=0.15 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/conda-package-streaming?source=hash-mapping + size: 21933 + timestamp: 1751548225624 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cpp-expected-1.3.1-h171cf75_0.conda + sha256: 0d9405d9f2de5d4b15d746609d87807aac10e269072d6408b769159762ed113d + md5: d17488e343e4c5c0bd0db18b3934d517 + depends: + - libstdcxx >=14 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + license: CC0-1.0 + purls: [] + size: 24283 + timestamp: 1756734785482 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cpp-expected-1.3.1-hdc560ac_0.conda + sha256: 4edebca2a9dadd8afabb3948a007edae2072e4869d8959b3e51aebc2367e1df4 + md5: 13f0be21fdd39114c28501ac21f0dd00 + depends: + - libstdcxx >=14 + - libgcc >=14 + license: CC0-1.0 + purls: [] + size: 25132 + timestamp: 1756734793606 +- conda: https://conda.anaconda.org/conda-forge/osx-64/cpp-expected-1.3.1-h0ba0a54_0.conda + sha256: 3192481102b7ad011933620791355148c16fb29ab8e0dac657de5388c05f44e8 + md5: d788061f51b79dfcb6c1521507ca08c7 + depends: + - __osx >=10.13 + - libcxx >=19 + license: CC0-1.0 + purls: [] + size: 24618 + timestamp: 1756734941438 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cpp-expected-1.3.1-h4f10f1e_0.conda + sha256: a7380056125a29ddc4c4efc4e39670bc8002609c70f143d92df801b42e0b486f + md5: 5cb4f9b93055faf7b6ae76da6123f927 + depends: + - __osx >=11.0 + - libcxx >=19 + license: CC0-1.0 + purls: [] + size: 24960 + timestamp: 1756734870487 +- conda: https://conda.anaconda.org/conda-forge/win-64/cpp-expected-1.3.1-h477610d_0.conda + sha256: cd24ac6768812d53c3b14c29b468cc9a5516b71e1880d67f58d98d9787f4cc3a + md5: 444e9f7d9b3f69006c3af5db59e11364 + depends: + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + license: CC0-1.0 + purls: [] + size: 21733 + timestamp: 1756734797622 +- pypi: https://files.pythonhosted.org/packages/34/71/1ea5a7352ae516d5512d17babe7e1b87d9db5150b21f794b1377eac1edc0/cryptography-46.0.6-cp311-abi3-manylinux_2_28_x86_64.whl + name: cryptography + version: 46.0.6 + sha256: 22259338084d6ae497a19bae5d4c66b7ca1387d3264d1c2c0e72d9e9b6a77b97 + requires_dist: + - cffi>=1.14 ; python_full_version == '3.8.*' and platform_python_implementation != 'PyPy' + - cffi>=2.0.0 ; python_full_version >= '3.9' and platform_python_implementation != 'PyPy' + - typing-extensions>=4.13.2 ; python_full_version < '3.11' + - bcrypt>=3.1.5 ; extra == 'ssh' + - nox[uv]>=2024.4.15 ; extra == 'nox' + - cryptography-vectors==46.0.6 ; extra == 'test' + - pytest>=7.4.0 ; extra == 'test' + - pytest-benchmark>=4.0 ; extra == 'test' + - pytest-cov>=2.10.1 ; extra == 'test' + - pytest-xdist>=3.5.0 ; extra == 'test' + - pretend>=0.7 ; extra == 'test' + - certifi>=2024 ; extra == 'test' + - pytest-randomly ; extra == 'test-randomorder' + - sphinx>=5.3.0 ; extra == 'docs' + - sphinx-rtd-theme>=3.0.0 ; extra == 'docs' + - sphinx-inline-tabs ; extra == 'docs' + - pyenchant>=3 ; extra == 'docstest' + - readme-renderer>=30.0 ; extra == 'docstest' + - sphinxcontrib-spelling>=7.3.1 ; extra == 'docstest' + - build>=1.0.0 ; extra == 'sdist' + - ruff>=0.11.11 ; extra == 'pep8test' + - mypy>=1.14 ; extra == 'pep8test' + - check-sdist ; extra == 'pep8test' + - click>=8.0.1 ; extra == 'pep8test' + requires_python: '>=3.8,!=3.9.0,!=3.9.1' +- pypi: https://files.pythonhosted.org/packages/d4/12/123be7292674abf76b21ac1fc0e1af50661f0e5b8f0ec8285faac18eb99e/cryptography-46.0.6-cp311-abi3-manylinux_2_28_aarch64.whl + name: cryptography + version: 46.0.6 + sha256: 67177e8a9f421aa2d3a170c3e56eca4e0128883cf52a071a7cbf53297f18b175 + requires_dist: + - cffi>=1.14 ; python_full_version == '3.8.*' and platform_python_implementation != 'PyPy' + - cffi>=2.0.0 ; python_full_version >= '3.9' and platform_python_implementation != 'PyPy' + - typing-extensions>=4.13.2 ; python_full_version < '3.11' + - bcrypt>=3.1.5 ; extra == 'ssh' + - nox[uv]>=2024.4.15 ; extra == 'nox' + - cryptography-vectors==46.0.6 ; extra == 'test' + - pytest>=7.4.0 ; extra == 'test' + - pytest-benchmark>=4.0 ; extra == 'test' + - pytest-cov>=2.10.1 ; extra == 'test' + - pytest-xdist>=3.5.0 ; extra == 'test' + - pretend>=0.7 ; extra == 'test' + - certifi>=2024 ; extra == 'test' + - pytest-randomly ; extra == 'test-randomorder' + - sphinx>=5.3.0 ; extra == 'docs' + - sphinx-rtd-theme>=3.0.0 ; extra == 'docs' + - sphinx-inline-tabs ; extra == 'docs' + - pyenchant>=3 ; extra == 'docstest' + - readme-renderer>=30.0 ; extra == 'docstest' + - sphinxcontrib-spelling>=7.3.1 ; extra == 'docstest' + - build>=1.0.0 ; extra == 'sdist' + - ruff>=0.11.11 ; extra == 'pep8test' + - mypy>=1.14 ; extra == 'pep8test' + - check-sdist ; extra == 'pep8test' + - click>=8.0.1 ; extra == 'pep8test' + requires_python: '>=3.8,!=3.9.0,!=3.9.1' +- conda: https://conda.anaconda.org/conda-forge/osx-64/cryptography-41.0.7-py310h527a09d_1.conda + sha256: cb43f44af3ff4ec8ffb1517234075d39e64442ec75ce995f1e9bd8b032a8aef0 + md5: e5291aa101f6590559177df876cd0955 + depends: + - cffi >=1.12 + - openssl >=3.1.4,<4.0a0 + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + license: Apache-2.0 AND BSD-3-Clause AND PSF-2.0 AND MIT + license_family: BSD + purls: + - pkg:pypi/cryptography?source=hash-mapping + size: 1218731 + timestamp: 1701563760923 +- conda: https://conda.anaconda.org/conda-forge/osx-64/cryptography-41.0.7-py311h48c7838_1.conda + sha256: f4c5e683386acf06cfa85805d264c9cd540361ec6e86740cb03312e560aa706a + md5: 65293feff96135571de02c047ecbd5a2 + depends: + - cffi >=1.12 + - openssl >=3.1.4,<4.0a0 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: Apache-2.0 AND BSD-3-Clause AND PSF-2.0 AND MIT + license_family: BSD + purls: + - pkg:pypi/cryptography?source=hash-mapping + size: 1280957 + timestamp: 1701563770508 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cryptography-41.0.7-py310h4c55245_1.conda + sha256: 85ce5e6db3093fea6bb45c28d783db002339cc56b578789d6141b136a4266a59 + md5: 9d2f02b43aaceb00fbe294ce9e9646c6 + depends: + - cffi >=1.12 + - openssl >=3.1.4,<4.0a0 + - python >=3.10,<3.11.0a0 + - python >=3.10,<3.11.0a0 *_cpython + - python_abi 3.10.* *_cp310 + license: Apache-2.0 AND BSD-3-Clause AND PSF-2.0 AND MIT + license_family: BSD + purls: + - pkg:pypi/cryptography?source=hash-mapping + size: 1200542 + timestamp: 1701563810375 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cryptography-41.0.7-py311h08c85a6_1.conda + sha256: 9d51ba743069d19aae08361a7b051ca1f281fb3b3ccb162e96c2503cf5a7d365 + md5: 729546a91873db64ab8e675008845fb5 + depends: + - cffi >=1.12 + - openssl >=3.1.4,<4.0a0 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: Apache-2.0 AND BSD-3-Clause AND PSF-2.0 AND MIT + license_family: BSD + purls: + - pkg:pypi/cryptography?source=hash-mapping + size: 1263886 + timestamp: 1701563842828 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cxx-compiler-1.11.0-hfcd1e18_0.conda + sha256: 3fcc97ae3e89c150401a50a4de58794ffc67b1ed0e1851468fcc376980201e25 + md5: 5da8c935dca9186673987f79cef0b2a5 + depends: + - c-compiler 1.11.0 h4d9bdce_0 + - gxx + - gxx_linux-64 14.* + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 6635 + timestamp: 1753098722177 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cxx-compiler-1.11.0-h7b35c40_0.conda + sha256: b87cd33501867d999caa1a57e488e69dc9e08011ec8685586df754302247a7a4 + md5: 0234c63e6b36b1677fd6c5238ef0a4ec + depends: + - c-compiler 1.11.0 hdceaead_0 + - gxx + - gxx_linux-aarch64 14.* + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 6705 + timestamp: 1753098688728 +- conda: https://conda.anaconda.org/conda-forge/osx-64/cxx-compiler-1.10.0-h20888b2_0.conda + sha256: 15f6ea7258555b2e34d147d378f4e8e08343ca3e71a18bd98b89a3dbc43142a2 + md5: b3a935ade707c54ebbea5f8a7c6f4549 + depends: + - c-compiler 1.10.0 h09a7c41_0 + - clangxx_osx-64 18.* + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 6785 + timestamp: 1751115659099 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cxx-compiler-1.10.0-hba80287_0.conda + sha256: 52cbfc615a9727294fccdd507f11919ca01ff29bd928bb5aa0b211697a983e9f + md5: 7fca30a1585a85ec8ab63579afcac5d3 + depends: + - c-compiler 1.10.0 hdf49b6b_0 + - clangxx_osx-arm64 18.* + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 6784 + timestamp: 1751115541888 +- conda: https://conda.anaconda.org/conda-forge/win-64/cxx-compiler-1.11.0-h1c1089f_0.conda + sha256: c888f4fe9ec117c1c01bfaa4c722ca475ebbb341c92d1718afa088bb0d710619 + md5: 4d94d3c01add44dc9d24359edf447507 + depends: + - vs2022_win-64 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 6957 + timestamp: 1753098809481 +- pypi: https://files.pythonhosted.org/packages/2b/dd/437e601fa9d2b6bf8507256daf52196a226c3b340261f4cde8fac8e853ea/delocate-0.13.0-py3-none-any.whl + name: delocate + version: 0.13.0 + sha256: 11f7596f88984c33f76b27fe2eea7637d1ce369a9e0b6737bbc706b6426e862c + requires_dist: + - packaging>=20.9 + - typing-extensions>=4.12.2 + - macholib + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/89/74/bf0ea7b89e114af19a38c2341746fd1f17f1de23fa8d8019cbcd39719c5f/delvewheel-1.12.0-py3-none-any.whl + name: delvewheel + version: 1.12.0 + sha256: 659ef85a83e4503e037e65570f7a87d2ad4e0ee55dc2d19d9afed420a031caf0 + requires_dist: + - pefile>=2024.8.26 + requires_python: '>=3.9' +- 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/distro-1.9.0-pyhd8ed1ab_1.conda + sha256: 5603c7d0321963bb9b4030eadabc3fd7ca6103a38475b4e0ed13ed6d97c86f4e + md5: 0a2014fd9860f8b1eaa0b1f3d3771a08 + depends: + - python >=3.9 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/distro?source=hash-mapping + size: 41773 + timestamp: 1734729953882 +- pypi: https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl + name: docutils + version: 0.22.4 + sha256: d0013f540772d1420576855455d050a2180186c91c15779301ac2ccb3eeb68de + requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/linux-64/doxygen-1.13.2-h8e693c7_0.conda + sha256: 349c4c872357b4a533e127b2ade8533796e8e062abc2cd685756a1a063ae1e35 + md5: 0869f41ea5c64643dd2f5b47f32709ca + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libiconv >=1.17,<2.0a0 + - libstdcxx >=13 + license: GPL-2.0-only + license_family: GPL + purls: [] + size: 13148627 + timestamp: 1738164137421 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/doxygen-1.13.2-h5e0f5ae_0.conda + sha256: 671fc9849fcdb9138daf2ab6b2d45b0650055ba1496cda19c415f57cabc381b8 + md5: 9091aa1c92ed01d5fe3d34d7e585b6a1 + depends: + - libgcc >=13 + - libiconv >=1.17,<2.0a0 + - libstdcxx >=13 + license: GPL-2.0-only + license_family: GPL + purls: [] + size: 13227405 + timestamp: 1738171320483 +- conda: https://conda.anaconda.org/conda-forge/osx-64/doxygen-1.10.0-h5ff76d1_0.conda + sha256: c329a379f8bc8a66bb91527efca44fb17b35ccf6f1dd1efc6b439fafe9ff67d4 + md5: 4b0fd9ed5a22b919a04bc147f9d65654 + depends: + - libcxx >=15 + - libiconv >=1.17,<2.0a0 + license: GPL-2.0-only + license_family: GPL + purls: [] + size: 11525553 + timestamp: 1703609916595 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/doxygen-1.10.0-h8fbad5d_0.conda + sha256: d609f61b22cb7fc5441a5bf1e6ac989840977cc682e94d726fdcc74c6cd89ea2 + md5: 80aaa05136ea0b7cea754bb28488cc0f + depends: + - libcxx >=15 + - libiconv >=1.17,<2.0a0 + license: GPL-2.0-only + license_family: GPL + purls: [] + size: 10593614 + timestamp: 1703609902689 +- conda: https://conda.anaconda.org/conda-forge/win-64/doxygen-1.13.2-hbf3f430_0.conda + sha256: 7a0fd40fd704e97a8f6533a081ba29579766d7a60bcb8e5de76679b066c4a72e + md5: 5cb2e11931773612d7a24b53f0c57594 + depends: + - libiconv >=1.17,<2.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + license: GPL-2.0-only + license_family: GPL + purls: [] + size: 9219343 + timestamp: 1738165042524 +- conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + sha256: ee6cf346d017d954255bbcbdb424cddea4d14e4ed7e9813e429db1d795d01144 + md5: 8e662bd460bda79b1ea39194e3c4c9ab + depends: + - python >=3.10 + - typing_extensions >=4.6.0 + license: MIT and PSF-2.0 + purls: + - pkg:pypi/exceptiongroup?source=hash-mapping + size: 21333 + timestamp: 1763918099466 +- conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda + sha256: dddea9ec53d5e179de82c24569d41198f98db93314f0adae6b15195085d5567f + md5: f58064cec97b12a7136ebb8a6f8a129b + depends: + - python >=3.10 + license: Unlicense + purls: + - pkg:pypi/filelock?source=compressed-mapping + size: 25845 + timestamp: 1773314012590 +- conda: https://conda.anaconda.org/conda-forge/linux-64/fmt-12.1.0-hff5e90c_0.conda + sha256: d4e92ba7a7b4965341dc0fca57ec72d01d111b53c12d11396473115585a9ead6 + md5: f7d7a4104082b39e3b3473fbd4a38229 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + license: MIT + license_family: MIT + purls: [] + size: 198107 + timestamp: 1767681153946 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/fmt-12.1.0-h20c602a_0.conda + sha256: 7826619c80af5a5fb0c1f2a965c93f4b92670523e12ff45c592daa3f11340746 + md5: 067209b690c2d7f42e1e4c370d1aff12 + depends: + - libgcc >=14 + - libstdcxx >=14 + license: MIT + license_family: MIT + purls: [] + size: 197671 + timestamp: 1767681179883 +- conda: https://conda.anaconda.org/conda-forge/osx-64/fmt-12.1.0-hda137b5_0.conda + sha256: 3c56fc4b3528acb29d89d139f9800b86425e643be8d9caddd4d6f4a8b09a8db4 + md5: 265ec3c628a7e2324d86a08205ada7a8 + depends: + - __osx >=10.13 + - libcxx >=19 + license: MIT + license_family: MIT + purls: [] + size: 188352 + timestamp: 1767681462452 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/fmt-12.1.0-h403dcb5_0.conda + sha256: dba5d4a93dc62f20e4c2de813ccf7beefed1fb54313faff9c4f2383e4744c8e5 + md5: ae2f556fbb43e5a75cc80a47ac942a8e + depends: + - __osx >=11.0 + - libcxx >=19 + license: MIT + license_family: MIT + purls: [] + size: 180970 + timestamp: 1767681372955 +- conda: https://conda.anaconda.org/conda-forge/win-64/fmt-12.1.0-h7f4e812_0.conda + sha256: cce96406ec353692ab46cd9d992eddb6923979c1a342cbdba33521a7c234176f + md5: 6e226b58e18411571aaa57a16ad10831 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: MIT + license_family: MIT + purls: [] + size: 186390 + timestamp: 1767681264793 +- conda: https://conda.anaconda.org/conda-forge/linux-64/frozendict-2.4.7-py310h7c4b9e2_0.conda + sha256: 584dd9b80818771700875465b2906a4a8cc1e766d802ce269a00d8622b92e522 + md5: 901de6f1f35f811f8d194785838a5977 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + license: LGPL-3.0-only + license_family: LGPL + purls: + - pkg:pypi/frozendict?source=hash-mapping + size: 49924 + timestamp: 1763082943540 +- conda: https://conda.anaconda.org/conda-forge/linux-64/frozendict-2.4.7-py311h49ec1c0_0.conda + sha256: df99ccc63c065875cc150f451aaab03e6733898219cf2f248543fe53b08deff0 + md5: cfc74ea184e02e531732abb17778e9fc + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: LGPL-3.0-only + license_family: LGPL + purls: + - pkg:pypi/frozendict?source=hash-mapping + size: 32010 + timestamp: 1763082979695 +- conda: https://conda.anaconda.org/conda-forge/linux-64/frozendict-2.4.7-py314h5bd0f2a_0.conda + sha256: 3e04b8293122e923f1c66599525e8b0e743f532b5c53d932c41105311b721526 + md5: 7a884102c0e9fb57012a6f49259475fc + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + license: LGPL-3.0-only + license_family: LGPL + purls: + - pkg:pypi/frozendict?source=hash-mapping + size: 31627 + timestamp: 1763082886391 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/frozendict-2.4.7-py310h5b55623_0.conda + sha256: bc856378ebcd12d761a9992cdb37719ea1dfed9c8b77e45951723aefbe8cd7da + md5: 31ee97292b96431bdafcc3af09c21550 + depends: + - libgcc >=14 + - python >=3.10,<3.11.0a0 + - python >=3.10,<3.11.0a0 *_cpython + - python_abi 3.10.* *_cp310 + license: LGPL-3.0-only + license_family: LGPL + purls: + - pkg:pypi/frozendict?source=hash-mapping + size: 51959 + timestamp: 1763082951492 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/frozendict-2.4.7-py311h19352d5_0.conda + sha256: 0951b89bc10e54b5e20c6bd8ef990e5afc155d13d713c45a525fe87f478980a6 + md5: 9ef6a694ecd981dad43ab8f1864bcf43 + depends: + - libgcc >=14 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: LGPL-3.0-only + license_family: LGPL + purls: + - pkg:pypi/frozendict?source=hash-mapping + size: 32258 + timestamp: 1763083003765 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/frozendict-2.4.7-py314h51f160d_0.conda + sha256: 669bfad0045393c79ad96fea1900d30d9c497cde6dd79ff6500be53245874c67 + md5: 723828d9832e586bf2f9c52c38d4bf01 + depends: + - libgcc >=14 + - python >=3.14,<3.15.0a0 + - python >=3.14,<3.15.0a0 *_cp314 + - python_abi 3.14.* *_cp314 + license: LGPL-3.0-only + license_family: LGPL + purls: + - pkg:pypi/frozendict?source=hash-mapping + size: 31504 + timestamp: 1763082941890 +- conda: https://conda.anaconda.org/conda-forge/osx-64/frozendict-2.4.7-py314h6482030_0.conda + sha256: 5d0f185b622da1bd23beafb7e66dc14d3d1335f1c3e7eca91e731f2ded12800b + md5: d7ab51dbffe250c5570d766c44db6af0 + depends: + - __osx >=10.13 + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + license: LGPL-3.0-only + license_family: LGPL + purls: + - pkg:pypi/frozendict?source=hash-mapping + size: 31842 + timestamp: 1763083176058 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/frozendict-2.4.7-py314h0612a62_0.conda + sha256: 614c604a4ff2ee59579d6ad6489726b56027bd49f50f4674cdaf98c6a0daa6be + md5: 8e7628502497ee2940f8864a22e3bd0c + depends: + - __osx >=11.0 + - python >=3.14,<3.15.0a0 + - python >=3.14,<3.15.0a0 *_cp314 + - python_abi 3.14.* *_cp314 + license: LGPL-3.0-only + license_family: LGPL + purls: + - pkg:pypi/frozendict?source=hash-mapping + size: 32182 + timestamp: 1763083208667 +- conda: https://conda.anaconda.org/conda-forge/win-64/frozendict-2.4.7-py310h29418f3_0.conda + sha256: 0d07dddfc0fcaf7532b2d7b70619422116f95296d68d714686c32b3eb431c218 + md5: 76c23d3bc5ebfa998703241569ee7b7e + depends: + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: LGPL-3.0-only + license_family: LGPL + purls: + - pkg:pypi/frozendict?source=hash-mapping + size: 47769 + timestamp: 1763083252959 +- conda: https://conda.anaconda.org/conda-forge/win-64/frozendict-2.4.7-py311h3485c13_0.conda + sha256: 2f719c3f15a54d02b5970075d013440eb9cc16503128cd9a8e97cb6275c57c82 + md5: b17cb83dcb04b06a3377c3ce8423bca9 + depends: + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: LGPL-3.0-only + license_family: LGPL + purls: + - pkg:pypi/frozendict?source=hash-mapping + size: 32227 + timestamp: 1763083050764 +- conda: https://conda.anaconda.org/conda-forge/win-64/frozendict-2.4.7-py314h5a2d7ad_0.conda + sha256: 87f206e4ac1ee9cc7099f3bbb05c039650b9a606bebb59c3778e5f2050795930 + md5: dbac0ebdc50febbb706fcd765227c90f + depends: + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: LGPL-3.0-only + license_family: LGPL + purls: + - pkg:pypi/frozendict?source=hash-mapping + size: 32072 + timestamp: 1763082973024 +- conda: https://conda.anaconda.org/conda-forge/linux-64/gcc-14.3.0-h0dff253_18.conda + sha256: 9b34b57b06b485e33a40d430f71ac88c8f381673592507cf7161c50ff0832772 + md5: 52d6457abc42e320787ada5f9033fa99 + depends: + - conda-gcc-specs + - gcc_impl_linux-64 14.3.0 hbdf3cc3_18 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 29506 + timestamp: 1771378321585 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gcc-14.3.0-h2e72a27_18.conda + sha256: debc5c801b3af35f1d474aead8621c4869a022d35ca3c5195a9843d81c1c9ab4 + md5: db4bf1a70c2481c06fe8174390a325c0 + depends: + - conda-gcc-specs + - gcc_impl_linux-aarch64 14.3.0 h533bfc8_18 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 29438 + timestamp: 1771378102660 +- conda: https://conda.anaconda.org/conda-forge/linux-64/gcc_impl_linux-64-14.3.0-hbdf3cc3_18.conda + sha256: 3b31a273b806c6851e16e9cf63ef87cae28d19be0df148433f3948e7da795592 + md5: 30bb690150536f622873758b0e8d6712 + depends: + - binutils_impl_linux-64 >=2.45 + - libgcc >=14.3.0 + - libgcc-devel_linux-64 14.3.0 hf649bbc_118 + - libgomp >=14.3.0 + - libsanitizer 14.3.0 h8f1669f_18 + - libstdcxx >=14.3.0 + - libstdcxx-devel_linux-64 14.3.0 h9f08a49_118 + - sysroot_linux-64 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 76302378 + timestamp: 1771378056505 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gcc_impl_linux-aarch64-14.3.0-h533bfc8_18.conda + sha256: e2488aac8472cfdff4f8a893861acd1ce1c66eafb28e7585ec52fe4e7546df7e + md5: 2ac1b579c1560e021a4086d0d704e2be + depends: + - binutils_impl_linux-aarch64 >=2.45 + - libgcc >=14.3.0 + - libgcc-devel_linux-aarch64 14.3.0 h25ba3ff_118 + - libgomp >=14.3.0 + - libsanitizer 14.3.0 hedb4206_18 + - libstdcxx >=14.3.0 + - libstdcxx-devel_linux-aarch64 14.3.0 h57c8d61_118 + - sysroot_linux-aarch64 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 69149627 + timestamp: 1771377858762 +- conda: https://conda.anaconda.org/conda-forge/linux-64/gcc_linux-64-14.3.0-h298d278_21.conda + sha256: 27ad0cd10dccffca74e20fb38c9f8643ff8fce56eee260bf89fa257d5ab0c90a + md5: 1403ed5fe091bd7442e4e8a229d14030 + depends: + - gcc_impl_linux-64 14.3.0.* + - binutils_linux-64 + - sysroot_linux-64 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 28946 + timestamp: 1770908213807 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gcc_linux-aarch64-14.3.0-h118592a_21.conda + sha256: 2b4c579549e63f8f7e29aa332a95b85a5a33976d6caf42d7c3dc147d2939d7a0 + md5: dfe811f86ef2d8f511263ef38b773a39 + depends: + - gcc_impl_linux-aarch64 14.3.0.* + - binutils_linux-aarch64 + - sysroot_linux-aarch64 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 28666 + timestamp: 1770908257439 +- conda: https://conda.anaconda.org/conda-forge/linux-64/gh-2.88.1-h76a2195_0.conda + sha256: 78f9fbbf18272e92e62bc1672d34178760ced73edc1e818ebd5fd00296b5df88 + md5: 0290cdefa20d98adb936c465ccb76ad6 + depends: + - __glibc >=2.17,<3.0.a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 22875681 + timestamp: 1773332470542 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gh-2.88.1-h94b2740_0.conda + sha256: bfa267b3a68c629b8d5a3bbb06dc828ba724f68a1e10aa5cc62667cca690d16a + md5: e1f7ec5f227660d3e0ce658e9acb3827 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 20986983 + timestamp: 1773335353762 +- conda: https://conda.anaconda.org/conda-forge/osx-64/gh-2.88.1-hdaada87_0.conda + sha256: c587e956e14f06b8517923864410e612c7882bac57cc7f1b5b11398f907362f9 + md5: af030582e521e76176f9765bd0d623a8 + depends: + - __osx >=11.0 + constrains: + - __osx>=10.12 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 23106117 + timestamp: 1773333114711 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/gh-2.88.1-h01237fd_0.conda + sha256: ed5ac50ece778e035d7739dc7547023c0391b44d20b98d7ef473b06cbdb5d040 + md5: 1bb23382c23eae0e52a48bfd4c3cd5e6 + depends: + - __osx >=11.0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 21742200 + timestamp: 1773332985739 +- conda: https://conda.anaconda.org/conda-forge/win-64/gh-2.88.1-h36e2d1d_0.conda + sha256: b286e07b5aa44db0e4969789da8b27ec62974108efd45900a444b72f32941859 + md5: 70ee65f0ce705a07b4848aec9ce97014 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 22357323 + timestamp: 1773332611831 +- conda: https://conda.anaconda.org/conda-forge/win-64/git-2.53.0-h57928b3_0.conda + sha256: 6bc7eb1202395c044ff24f175f9f6d594bdc4c620e0cfa9e03ed46ef34c265ba + md5: b63e3ad61f7507fc72479ab0dde1a6be + license: GPL-2.0-or-later and LGPL-2.1-or-later + purls: [] + size: 123465948 + timestamp: 1770982612399 +- conda: https://conda.anaconda.org/conda-forge/linux-64/gxx-14.3.0-h76987e4_18.conda + sha256: 1b490c9be9669f9c559db7b2a1f7d8b973c58ca0c6f21a5d2ba3f0ab2da63362 + md5: 19189121d644d4ef75fed05383bc75f5 + depends: + - gcc 14.3.0 h0dff253_18 + - gxx_impl_linux-64 14.3.0 h2185e75_18 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 28883 + timestamp: 1771378355605 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gxx-14.3.0-ha384071_18.conda + sha256: 09fb56bcb1594d667e39b1ff4fced377f1b3f6c83f5b651d500db0b4865df68a + md5: 3d5380505980f8859a796af4c1b49452 + depends: + - gcc 14.3.0 h2e72a27_18 + - gxx_impl_linux-aarch64 14.3.0 h0d4f5d4_18 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 28822 + timestamp: 1771378129202 +- conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_impl_linux-64-14.3.0-h2185e75_18.conda + sha256: 38ffca57cc9c264d461ac2ce9464a9d605e0f606d92d831de9075cb0d95fc68a + md5: 6514b3a10e84b6a849e1b15d3753eb22 + depends: + - gcc_impl_linux-64 14.3.0 hbdf3cc3_18 + - libstdcxx-devel_linux-64 14.3.0 h9f08a49_118 + - sysroot_linux-64 + - tzdata + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 14566100 + timestamp: 1771378271421 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gxx_impl_linux-aarch64-14.3.0-h0d4f5d4_18.conda + sha256: 859a78ff16bef8d1d1d89d0604929c3c256ac0248b9a688e8defe9bbc027c886 + md5: a12277d1ec675dbb993ad72dce735530 + depends: + - gcc_impl_linux-aarch64 14.3.0 h533bfc8_18 + - libstdcxx-devel_linux-aarch64 14.3.0 h57c8d61_118 + - sysroot_linux-aarch64 + - tzdata + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 13513218 + timestamp: 1771378064341 +- conda: https://conda.anaconda.org/conda-forge/linux-64/gxx_linux-64-14.3.0-he467f4b_21.conda + sha256: 1e07c197e0779fa9105e59cd55a835ded96bfde59eb169439736a89b27b48e5d + md5: 7b51f4ff82eeb1f386bfee20a7bed3ed + depends: + - gxx_impl_linux-64 14.3.0.* + - gcc_linux-64 ==14.3.0 h298d278_21 + - binutils_linux-64 + - sysroot_linux-64 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 27503 + timestamp: 1770908213813 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/gxx_linux-aarch64-14.3.0-h32e4f2e_21.conda + sha256: 10059135f9960de93f991ce7fb6ef9d833dc2ac675459a1a08def052e5a29667 + md5: 3114b029596eff0aeb9fc0c81f598211 + depends: + - gxx_impl_linux-aarch64 14.3.0.* + - gcc_linux-aarch64 ==14.3.0 h118592a_21 + - binutils_linux-aarch64 + - sysroot_linux-aarch64 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 27275 + timestamp: 1770908257444 +- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda + sha256: 84c64443368f84b600bfecc529a1194a3b14c3656ee2e832d15a20e0329b6da3 + md5: 164fc43f0b53b6e3a7bc7dce5e4f1dc9 + depends: + - python >=3.10 + - hyperframe >=6.1,<7 + - hpack >=4.1,<5 + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/h2?source=hash-mapping + size: 95967 + timestamp: 1756364871835 +- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda + sha256: 6ad78a180576c706aabeb5b4c8ceb97c0cb25f1e112d76495bff23e3779948ba + md5: 0a802cb9888dd14eeefc611f05c40b6e + depends: + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/hpack?source=hash-mapping + size: 30731 + timestamp: 1737618390337 +- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda + sha256: 77af6f5fe8b62ca07d09ac60127a30d9069fdc3c68d6b256754d0ffb1f7779f8 + md5: 8e6923fc12f1fe8f8c4e5c9f343256ac + depends: + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/hyperframe?source=hash-mapping + size: 17397 + timestamp: 1737618427549 +- conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.2-h33c6efd_0.conda + sha256: 142a722072fa96cf16ff98eaaf641f54ab84744af81754c292cb81e0881c0329 + md5: 186a18e3ba246eccfc7cff00cd19a870 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + license: MIT + license_family: MIT + purls: [] + size: 12728445 + timestamp: 1767969922681 +- conda: https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-h33c6efd_0.conda + sha256: fbf86c4a59c2ed05bbffb2ba25c7ed94f6185ec30ecb691615d42342baa1a16a + md5: c80d8a3b84358cb967fa81e7075fbc8a + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + license: MIT + license_family: MIT + purls: [] + size: 12723451 + timestamp: 1773822285671 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/icu-78.2-hcab7f73_0.conda + sha256: dcbaa3042084ac58685e3ef4547e4c4be9d37dc52b92ea18581288af95e48b52 + md5: 998ee7d53e32f7ab57fc35707285527e + depends: + - libgcc >=14 + - libstdcxx >=14 + license: MIT + license_family: MIT + purls: [] + size: 12851689 + timestamp: 1772208964788 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/icu-78.3-hcab7f73_0.conda + sha256: 49ba6aed2c6b482bb0ba41078057555d29764299bc947b990708617712ef6406 + md5: 546da38c2fa9efacf203e2ad3f987c59 + depends: + - libgcc >=14 + - libstdcxx >=14 + license: MIT + license_family: MIT + purls: [] + size: 12837286 + timestamp: 1773822650615 +- conda: https://conda.anaconda.org/conda-forge/osx-64/icu-73.2-hf5e326d_0.conda + sha256: f66362dc36178ac9b7c7a9b012948a9d2d050b3debec24bbd94aadbc44854185 + md5: 5cc301d759ec03f28328428e28f65591 + license: MIT + license_family: MIT + purls: [] + size: 11787527 + timestamp: 1692901622519 +- conda: https://conda.anaconda.org/conda-forge/osx-64/icu-78.2-h14c5de8_0.conda + sha256: f3066beae7fe3002f09c8a412cdf1819f49a2c9a485f720ec11664330cf9f1fe + md5: 30334add4de016489b731c6662511684 + depends: + - __osx >=10.13 + license: MIT + license_family: MIT + size: 12263724 + timestamp: 1767970604977 +- conda: https://conda.anaconda.org/conda-forge/osx-64/icu-78.3-h25d91c4_0.conda + sha256: 1294117122d55246bb83ad5b589e2a031aacdf2d0b1f99fd338aa4394f881735 + md5: 627eca44e62e2b665eeec57a984a7f00 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 12273764 + timestamp: 1773822733780 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-73.2-hc8870d7_0.conda + sha256: ff9cd0c6cd1349954c801fb443c94192b637e1b414514539f3c49c56a39f51b1 + md5: 8521bd47c0e11c5902535bb1a17c565f + license: MIT + license_family: MIT + purls: [] + size: 11997841 + timestamp: 1692902104771 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.2-hef89b57_0.conda + sha256: 24bc62335106c30fecbcc1dba62c5eba06d18b90ea1061abd111af7b9c89c2d7 + md5: 114e6bfe7c5ad2525eb3597acdbf2300 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + size: 12389400 + timestamp: 1772209104304 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-hef89b57_0.conda + sha256: 3a7907a17e9937d3a46dfd41cffaf815abad59a569440d1e25177c15fd0684e5 + md5: f1182c91c0de31a7abd40cedf6a5ebef + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 12361647 + timestamp: 1773822915649 +- pypi: https://files.pythonhosted.org/packages/42/77/de194443bf38daed9452139e960c632b0ef9f9a5dd9ce605fdf18ca9f1b1/id-1.6.1-py3-none-any.whl + name: id + version: 1.6.1 + sha256: f5ec41ed2629a508f5d0988eda142e190c9c6da971100612c4de9ad9f9b237ca + requires_dist: + - urllib3>=2,<3 + - build ; extra == 'dev' + - bump>=1.3.2 ; extra == 'dev' + - id[test,lint] ; extra == 'dev' + - bandit ; extra == 'lint' + - interrogate ; extra == 'lint' + - mypy ; extra == 'lint' + - ruff<0.14.15 ; extra == 'lint' + - pytest ; extra == 'test' + - pytest-cov ; extra == 'test' + - pretend ; extra == 'test' + - coverage[toml] ; extra == 'test' + requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda + sha256: 3bae1b612ccc71e49c5795a369a82c4707ae6fd4e63360e8ecc129f9539f779b + md5: 635d1a924e1c55416fce044ed96144a2 + depends: + - python >=3.10 + - ukkonen + license: MIT + license_family: MIT + purls: + - pkg:pypi/identify?source=hash-mapping + size: 79749 + timestamp: 1774239544252 +- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda + sha256: ae89d0299ada2a3162c2614a9d26557a92aa6a77120ce142f8e0109bbf0342b0 + md5: 53abe63df7e10a6ba605dc5f9f961d36 + depends: + - python >=3.10 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/idna?source=hash-mapping + size: 50721 + timestamp: 1760286526795 +- 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-metadata-8.8.0-pyhcf101f3_0.conda + sha256: 82ab2a0d91ca1e7e63ab6a4939356667ef683905dea631bc2121aa534d347b16 + md5: 080594bf4493e6bae2607e65390c520a + depends: + - python >=3.10 + - zipp >=3.20 + - python + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/importlib-metadata?source=compressed-mapping + size: 34387 + timestamp: 1773931568510 +- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-resources-6.5.2-pyhd8ed1ab_0.conda + sha256: a99a3dafdfff2bb648d2b10637c704400295cb2ba6dc929e2d814870cf9f6ae5 + md5: e376ea42e9ae40f3278b0f79c9bf9826 + depends: + - importlib_resources >=6.5.2,<6.5.3.0a0 + - python >=3.9 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 9724 + timestamp: 1736252443859 +- conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda + sha256: acc1d991837c0afb67c75b77fdc72b4bf022aac71fedd8b9ea45918ac9b08a80 + md5: c85c76dc67d75619a92f51dfbce06992 + depends: + - python >=3.9 + - zipp >=3.1.0 + constrains: + - importlib-resources >=6.5.2,<6.5.3.0a0 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/importlib-resources?source=hash-mapping + size: 33781 + timestamp: 1736252433366 +- pypi: https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl + name: jaraco-classes + version: 3.4.0 + sha256: f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790 + requires_dist: + - more-itertools + - sphinx>=3.5 ; extra == 'docs' + - jaraco-packaging>=9.3 ; extra == 'docs' + - rst-linker>=1.9 ; extra == 'docs' + - furo ; extra == 'docs' + - sphinx-lint ; extra == 'docs' + - jaraco-tidelift>=1.4 ; extra == 'docs' + - pytest>=6 ; extra == 'testing' + - pytest-checkdocs>=2.4 ; extra == 'testing' + - pytest-cov ; extra == 'testing' + - pytest-mypy ; extra == 'testing' + - pytest-enabler>=2.2 ; extra == 'testing' + - pytest-ruff>=0.2.1 ; extra == 'testing' + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl + name: jaraco-context + version: 6.1.2 + sha256: bf8150b79a2d5d91ae48629d8b427a8f7ba0e1097dd6202a9059f29a36379535 + requires_dist: + - backports-tarfile ; python_full_version < '3.12' + - pytest>=6,!=8.1.* ; extra == 'test' + - jaraco-test>=5.6.0 ; extra == 'test' + - portend ; extra == 'test' + - sphinx>=3.5 ; extra == 'doc' + - jaraco-packaging>=9.3 ; extra == 'doc' + - rst-linker>=1.9 ; extra == 'doc' + - furo ; extra == 'doc' + - sphinx-lint ; extra == 'doc' + - jaraco-tidelift>=1.4 ; extra == 'doc' + - pytest-checkdocs>=2.14 ; extra == 'check' + - pytest-ruff>=0.2.1 ; sys_platform != 'cygwin' and extra == 'check' + - pytest-cov ; extra == 'cover' + - pytest-enabler>=3.4 ; extra == 'enabler' + - pytest-mypy>=1.0.1 ; platform_python_implementation != 'PyPy' and extra == 'type' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/fd/c4/813bb09f0985cb21e959f21f2464169eca882656849adf727ac7bb7e1767/jaraco_functools-4.4.0-py3-none-any.whl + name: jaraco-functools + version: 4.4.0 + sha256: 9eec1e36f45c818d9bf307c8948eb03b2b56cd44087b3cdc989abca1f20b9176 + requires_dist: + - more-itertools + - pytest>=6,!=8.1.* ; extra == 'test' + - jaraco-classes ; extra == 'test' + - sphinx>=3.5 ; extra == 'doc' + - jaraco-packaging>=9.3 ; extra == 'doc' + - rst-linker>=1.9 ; extra == 'doc' + - furo ; extra == 'doc' + - sphinx-lint ; extra == 'doc' + - jaraco-tidelift>=1.4 ; extra == 'doc' + - pytest-checkdocs>=2.4 ; extra == 'check' + - pytest-ruff>=0.2.1 ; sys_platform != 'cygwin' and extra == 'check' + - pytest-cov ; extra == 'cover' + - pytest-enabler>=3.4 ; extra == 'enabler' + - pytest-mypy>=1.0.1 ; extra == 'type' + - mypy<1.19 ; platform_python_implementation == 'PyPy' and extra == 'type' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl + name: jeepney + version: 0.9.0 + sha256: 97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683 + requires_dist: + - pytest ; extra == 'test' + - pytest-trio ; extra == 'test' + - pytest-asyncio>=0.17 ; extra == 'test' + - testpath ; extra == 'test' + - trio ; extra == 'test' + - async-timeout ; python_full_version < '3.11' and extra == 'test' + - trio ; extra == 'trio' + requires_python: '>=3.7' +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda + sha256: 304955757d1fedbe344af43b12b5467cca072f83cce6109361ba942e186b3993 + md5: cb60ae9cf02b9fcb8004dec4089e5691 + depends: + - jsonpointer >=1.9 + - python >=3.9 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/jsonpatch?source=hash-mapping + size: 17311 + timestamp: 1733814664790 +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.0.0-pyhcf101f3_3.conda + sha256: 1a1328476d14dfa8b84dbacb7f7cd7051c175498406dc513ca6c679dc44f3981 + md5: cd2214824e36b0180141d422aba01938 + depends: + - python >=3.10 + - python + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/jsonpointer?source=hash-mapping + size: 13967 + timestamp: 1765026384757 +- conda: https://conda.anaconda.org/conda-forge/noarch/jsonpointer-3.1.1-pyhcf101f3_0.conda + sha256: a3d10301b6ff399ba1f3d39e443664804a3d28315a4fb81e745b6817845f70ae + md5: 89bf346df77603055d3c8fe5811691e6 + depends: + - python >=3.10 + - python + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/jsonpointer?source=compressed-mapping + size: 14190 + timestamp: 1774311356147 +- conda: https://conda.anaconda.org/conda-forge/noarch/kernel-headers_linux-64-4.18.0-he073ed8_9.conda + sha256: 41557eeadf641de6aeae49486cef30d02a6912d8da98585d687894afd65b356a + md5: 86d9cba083cd041bfbf242a01a7a1999 + constrains: + - sysroot_linux-64 ==2.28 + license: LGPL-2.0-or-later AND LGPL-2.0-or-later WITH exceptions AND GPL-2.0-or-later + license_family: GPL + purls: [] + size: 1278712 + timestamp: 1765578681495 +- conda: https://conda.anaconda.org/conda-forge/noarch/kernel-headers_linux-aarch64-4.18.0-h05a177a_9.conda + sha256: 5d224bf4df9bac24e69de41897c53756108c5271a0e5d2d2f66fd4e2fbc1d84b + md5: bb3b7cad9005f2cbf9d169fb30263f3e + constrains: + - sysroot_linux-aarch64 ==2.28 + license: LGPL-2.0-or-later AND LGPL-2.0-or-later WITH exceptions AND GPL-2.0-or-later + license_family: GPL + purls: [] + size: 1248134 + timestamp: 1765578613607 +- pypi: https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl + name: keyring + version: 25.7.0 + sha256: be4a0b195f149690c166e850609a477c532ddbfbaed96a404d4e43f8d5e2689f + requires_dist: + - pywin32-ctypes>=0.2.0 ; sys_platform == 'win32' + - secretstorage>=3.2 ; sys_platform == 'linux' + - jeepney>=0.4.2 ; sys_platform == 'linux' + - importlib-metadata>=4.11.4 ; python_full_version < '3.12' + - jaraco-classes + - jaraco-functools + - jaraco-context + - pytest>=6,!=8.1.* ; extra == 'test' + - pyfakefs ; extra == 'test' + - sphinx>=3.5 ; extra == 'doc' + - jaraco-packaging>=9.3 ; extra == 'doc' + - rst-linker>=1.9 ; extra == 'doc' + - furo ; extra == 'doc' + - sphinx-lint ; extra == 'doc' + - jaraco-tidelift>=1.4 ; extra == 'doc' + - pytest-checkdocs>=2.4 ; extra == 'check' + - pytest-ruff>=0.2.1 ; sys_platform != 'cygwin' and extra == 'check' + - pytest-cov ; extra == 'cover' + - pytest-enabler>=3.4 ; extra == 'enabler' + - pytest-mypy>=1.0.1 ; extra == 'type' + - pygobject-stubs ; extra == 'type' + - shtab ; extra == 'type' + - types-pywin32 ; extra == 'type' + - shtab>=1.1.0 ; extra == 'completion' + requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda + sha256: 0960d06048a7185d3542d850986d807c6e37ca2e644342dd0c72feefcf26c2a4 + md5: b38117a3c920364aff79f870c984b4a3 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: LGPL-2.1-or-later + purls: [] + size: 134088 + timestamp: 1754905959823 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/keyutils-1.6.3-h86ecc28_0.conda + sha256: 5ce830ca274b67de11a7075430a72020c1fb7d486161a82839be15c2b84e9988 + md5: e7df0aab10b9cbb73ab2a467ebfaf8c7 + depends: + - libgcc >=13 + license: LGPL-2.1-or-later + purls: [] + size: 129048 + timestamp: 1754906002667 +- conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda + sha256: 3e307628ca3527448dd1cb14ad7bb9d04d1d28c7d4c5f97ba196ae984571dd25 + md5: fb53fb07ce46a575c5d004bbc96032c2 + depends: + - __glibc >=2.17,<3.0.a0 + - keyutils >=1.6.3,<2.0a0 + - libedit >=3.1.20250104,<3.2.0a0 + - libedit >=3.1.20250104,<4.0a0 + - libgcc >=14 + - libstdcxx >=14 + - openssl >=3.5.5,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 1386730 + timestamp: 1769769569681 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/krb5-1.22.2-hfd895c2_0.conda + sha256: b53999d888dda53c506b264e8c02b5f5c8e022c781eda0718f007339e6bc90ba + md5: d9ca108bd680ea86a963104b6b3e95ca + depends: + - keyutils >=1.6.3,<2.0a0 + - libedit >=3.1.20250104,<3.2.0a0 + - libedit >=3.1.20250104,<4.0a0 + - libgcc >=14 + - libstdcxx >=14 + - openssl >=3.5.5,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 1517436 + timestamp: 1769773395215 +- conda: https://conda.anaconda.org/conda-forge/osx-64/krb5-1.21.2-hb884880_0.conda + sha256: 081ae2008a21edf57c048f331a17c65d1ccb52d6ca2f87ee031a73eff4dc0fc6 + md5: 80505a68783f01dc8d7308c075261b2f + depends: + - libcxx >=15.0.7 + - libedit >=3.1.20191231,<3.2.0a0 + - libedit >=3.1.20191231,<4.0a0 + - openssl >=3.1.2,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 1183568 + timestamp: 1692098004387 +- conda: https://conda.anaconda.org/conda-forge/osx-64/krb5-1.22.2-h207b36a_0.conda + sha256: df009385e8262c234c0dae9016540b86dad3d299f0d9366d08e327e8e7731634 + md5: e66e2c52d2fdddcf314ad750fb4ebb4a + depends: + - __osx >=10.13 + - libcxx >=19 + - libedit >=3.1.20250104,<3.2.0a0 + - libedit >=3.1.20250104,<4.0a0 + - openssl >=3.5.5,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 1193620 + timestamp: 1769770267475 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.21.2-h92f50d5_0.conda + sha256: 70bdb9b4589ec7c7d440e485ae22b5a352335ffeb91a771d4c162996c3070875 + md5: 92f1cff174a538e0722bf2efb16fc0b2 + depends: + - libcxx >=15.0.7 + - libedit >=3.1.20191231,<3.2.0a0 + - libedit >=3.1.20191231,<4.0a0 + - openssl >=3.1.2,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 1195575 + timestamp: 1692098070699 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda + sha256: c0a0bf028fe7f3defcdcaa464e536cf1b202d07451e18ad83fdd169d15bef6ed + md5: e446e1822f4da8e5080a9de93474184d + depends: + - __osx >=11.0 + - libcxx >=19 + - libedit >=3.1.20250104,<3.2.0a0 + - libedit >=3.1.20250104,<4.0a0 + - openssl >=3.5.5,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 1160828 + timestamp: 1769770119811 +- conda: https://conda.anaconda.org/conda-forge/win-64/krb5-1.22.2-h0ea6238_0.conda + sha256: eb60f1ad8b597bcf95dee11bc11fe71a8325bc1204cf51d2bb1f2120ffd77761 + md5: 4432f52dc0c8eb6a7a6abc00a037d93c + depends: + - openssl >=3.5.5,<4.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: MIT + license_family: MIT + purls: [] + size: 751055 + timestamp: 1769769688841 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ld64-711-h4e51db5_0.conda + sha256: 230be4e751f17fa1ccc15066086d1726d1d223e98f8337f435b4472bfe00436b + md5: cc84dae1a60ee59f6098f93b76d74b60 + depends: + - ld64_osx-64 711 had5d0d3_0 + - libllvm18 >=18.1.1,<18.2.0a0 + constrains: + - cctools_osx-64 986.* + - cctools 986.* + license: APSL-2.0 + license_family: Other + purls: [] + size: 18568 + timestamp: 1710484499499 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ld64-711-h4c6efb1_0.conda + sha256: 467371e8dbd4fc99f507024c3d10c0ac4a8528286e9507a1f365e26cb90f4df0 + md5: 289df626863e8c720c3aa220964378cc + depends: + - ld64_osx-arm64 711 h5e7191b_0 + - libllvm18 >=18.1.1,<18.2.0a0 + constrains: + - cctools 986.* + - cctools_osx-arm64 986.* + license: APSL-2.0 + license_family: Other + purls: [] + size: 18678 + timestamp: 1710484665887 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ld64_osx-64-711-had5d0d3_0.conda + sha256: 14d3fd593a7fd1cc472167dc00fd1d3176b8ce9dfc9b9d003359ecde4ded7459 + md5: cb63e1d1e11a1fffad54333330486ddd + depends: + - libcxx + - libllvm18 >=18.1.1,<18.2.0a0 + - sigtool + - tapi >=1100.0.11,<1101.0a0 + constrains: + - cctools_osx-64 986.* + - ld 711.* + - cctools 986.* + - clang >=18.1.1,<19.0a0 + license: APSL-2.0 + license_family: Other + purls: [] + size: 1071472 + timestamp: 1710484364960 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ld64_osx-arm64-711-h5e7191b_0.conda + sha256: 82f964dcff2052b327762ca44651407451ad396a1540c664928841c72b7cf3c0 + md5: c751b76ae8112e3d516831063da179cc + depends: + - libcxx + - libllvm18 >=18.1.1,<18.2.0a0 + - sigtool + - tapi >=1100.0.11,<1101.0a0 + constrains: + - ld 711.* + - cctools 986.* + - cctools_osx-arm64 986.* + - clang >=18.1.1,<19.0a0 + license: APSL-2.0 + license_family: Other + purls: [] + size: 1064448 + timestamp: 1710484550965 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_101.conda + sha256: 565941ac1f8b0d2f2e8f02827cbca648f4d18cd461afc31f15604cd291b5c5f3 + md5: 12bd9a3f089ee6c9266a37dab82afabd + depends: + - __glibc >=2.17,<3.0.a0 + - zstd >=1.5.7,<1.6.0a0 + constrains: + - binutils_impl_linux-64 2.45.1 + license: GPL-3.0-only + license_family: GPL + purls: [] + size: 725507 + timestamp: 1770267139900 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda + sha256: 3d584956604909ff5df353767f3a2a2f60e07d070b328d109f30ac40cd62df6c + md5: 18335a698559cdbcd86150a48bf54ba6 + depends: + - __glibc >=2.17,<3.0.a0 + - zstd >=1.5.7,<1.6.0a0 + constrains: + - binutils_impl_linux-64 2.45.1 + license: GPL-3.0-only + license_family: GPL + purls: [] + size: 728002 + timestamp: 1774197446916 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.45.1-default_h1979696_101.conda + sha256: 44527364aa333be631913451c32eb0cae1e09343827e9ce3ccabd8d962584226 + md5: 35b2ae7fadf364b8e5fb8185aaeb80e5 + depends: + - zstd >=1.5.7,<1.6.0a0 + constrains: + - binutils_impl_linux-aarch64 2.45.1 + license: GPL-3.0-only + license_family: GPL + purls: [] + size: 875924 + timestamp: 1770267209884 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.45.1-default_h1979696_102.conda + sha256: 7abd913d81a9bf00abb699e8987966baa2065f5132e37e815f92d90fc6bba530 + md5: a21644fc4a83da26452a718dc9468d5f + depends: + - zstd >=1.5.7,<1.6.0a0 + constrains: + - binutils_impl_linux-aarch64 2.45.1 + license: GPL-3.0-only + license_family: GPL + purls: [] + size: 875596 + timestamp: 1774197520746 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.6-gpl_hc2c16d8_100.conda + sha256: 69ea8da58658ad26cb64fb0bfccd8a3250339811f0b57c6b8a742e5e51bacf70 + md5: 981d372c31a23e1aa9965d4e74d085d5 + depends: + - __glibc >=2.17,<3.0.a0 + - bzip2 >=1.0.8,<2.0a0 + - libgcc >=14 + - liblzma >=5.8.2,<6.0a0 + - libxml2 + - libxml2-16 >=2.14.6 + - libzlib >=1.3.1,<2.0a0 + - lz4-c >=1.10.0,<1.11.0a0 + - lzo >=2.10,<3.0a0 + - openssl >=3.5.5,<4.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 887139 + timestamp: 1773243188979 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libarchive-3.8.6-gpl_hbe7d12b_100.conda + sha256: 635a78a04461e82150263ee9a1fbf6c965de0b811a10e87392a1e44be1115a39 + md5: f2c45cbb67fd0f668a1a0c152b70dc5f + depends: + - bzip2 >=1.0.8,<2.0a0 + - libgcc >=14 + - liblzma >=5.8.2,<6.0a0 + - libxml2 + - libxml2-16 >=2.14.6 + - libzlib >=1.3.1,<2.0a0 + - lz4-c >=1.10.0,<1.11.0a0 + - lzo >=2.10,<3.0a0 + - openssl >=3.5.5,<4.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 1000663 + timestamp: 1773243230880 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libarchive-3.8.6-gpl_h2bf6321_100.conda + sha256: 54a4e32132d45557e5f79ec88e4ab951c36fbd8acf256949121656c9f6979998 + md5: b69c2c71c786c9fd1524e69072e96bc7 + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libiconv >=1.18,<2.0a0 + - liblzma >=5.8.2,<6.0a0 + - libxml2 + - libxml2-16 >=2.14.6 + - libzlib >=1.3.1,<2.0a0 + - lz4-c >=1.10.0,<1.11.0a0 + - lzo >=2.10,<3.0a0 + - openssl >=3.5.5,<4.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 761501 + timestamp: 1773243700449 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libarchive-3.8.6-gpl_h6fbacd7_100.conda + sha256: 57fcc5cb6203cb0e119f46be708c8b2cf2bae47dc7580e5b4e76bd4b4c6d164a + md5: 4133c0cef1c6a25426b35f790e006648 + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libiconv >=1.18,<2.0a0 + - liblzma >=5.8.2,<6.0a0 + - libxml2 + - libxml2-16 >=2.14.6 + - libzlib >=1.3.1,<2.0a0 + - lz4-c >=1.10.0,<1.11.0a0 + - lzo >=2.10,<3.0a0 + - openssl >=3.5.5,<4.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 791560 + timestamp: 1773243648871 +- conda: https://conda.anaconda.org/conda-forge/win-64/libarchive-3.8.6-gpl_he24518a_100.conda + sha256: 0cc7f963d689fcadc0f7e83eb1f538ea73543af92e2b988d552a3d12cceb56e6 + md5: c76cc84cfafa74e43d8951db29983ebb + depends: + - bzip2 >=1.0.8,<2.0a0 + - liblzma >=5.8.2,<6.0a0 + - libxml2 + - libxml2-16 >=2.14.6 + - libzlib >=1.3.1,<2.0a0 + - lz4-c >=1.10.0,<1.11.0a0 + - lzo >=2.10,<3.0a0 + - openssl >=3.5.5,<4.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - zstd >=1.5.7,<1.6.0a0 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 1106665 + timestamp: 1773243755298 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-5_h4a7cf45_openblas.conda + build_number: 5 + sha256: 18c72545080b86739352482ba14ba2c4815e19e26a7417ca21a95b76ec8da24c + md5: c160954f7418d7b6e87eaf05a8913fa9 + depends: + - libopenblas >=0.3.30,<0.3.31.0a0 + - libopenblas >=0.3.30,<1.0a0 + constrains: + - mkl <2026 + - liblapack 3.11.0 5*_openblas + - libcblas 3.11.0 5*_openblas + - blas 2.305 openblas + - liblapacke 3.11.0 5*_openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 18213 + timestamp: 1765818813880 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libblas-3.11.0-5_haddc8a3_openblas.conda + build_number: 5 + sha256: 700f3c03d0fba8e687a345404a45fbabe781c1cf92242382f62cef2948745ec4 + md5: 5afcea37a46f76ec1322943b3c4dfdc0 + depends: + - libopenblas >=0.3.30,<0.3.31.0a0 + - libopenblas >=0.3.30,<1.0a0 + constrains: + - mkl <2026 + - libcblas 3.11.0 5*_openblas + - liblapack 3.11.0 5*_openblas + - liblapacke 3.11.0 5*_openblas + - blas 2.305 openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 18369 + timestamp: 1765818610617 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.9.0-22_osx64_openblas.conda + build_number: 22 + sha256: d72060239f904b3a81d2329efcf84dc62c2dfd66dbc4efc8dcae1afdf8f02b59 + md5: b80966a8c8dd0b531f8e65f709d732e8 + depends: + - libopenblas >=0.3.27,<0.3.28.0a0 + - libopenblas >=0.3.27,<1.0a0 + constrains: + - liblapacke 3.9.0 22_osx64_openblas + - blas * openblas + - libcblas 3.9.0 22_osx64_openblas + - liblapack 3.9.0 22_osx64_openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 14749 + timestamp: 1712542279018 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.9.0-24_osxarm64_openblas.conda + build_number: 24 + sha256: 4739f7463efb12e6d71536d8b0285a8de5aaadcc442bfedb9d92d1b4cbc47847 + md5: 35cb711e7bc46ee5f3dd67af99ad1986 + depends: + - libopenblas >=0.3.27,<0.3.28.0a0 + - libopenblas >=0.3.27,<1.0a0 + constrains: + - liblapack 3.9.0 24_osxarm64_openblas + - blas * openblas + - liblapacke 3.9.0 24_osxarm64_openblas + - libcblas 3.9.0 24_osxarm64_openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 15144 + timestamp: 1726668802976 +- conda: https://conda.anaconda.org/conda-forge/win-64/libblas-3.11.0-5_hf2e6a31_mkl.conda + build_number: 5 + sha256: f0cb7b2697461a306341f7ff32d5b361bb84f3e94478464c1e27ee01fc8f276b + md5: f9decf88743af85c9c9e05556a4c47c0 + depends: + - mkl >=2025.3.0,<2026.0a0 + constrains: + - liblapack 3.11.0 5*_mkl + - libcblas 3.11.0 5*_mkl + - blas 2.305 mkl + - liblapacke 3.11.0 5*_mkl + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 67438 + timestamp: 1765819100043 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-5_h0358290_openblas.conda + build_number: 5 + sha256: 0cbdcc67901e02dc17f1d19e1f9170610bd828100dc207de4d5b6b8ad1ae7ad8 + md5: 6636a2b6f1a87572df2970d3ebc87cc0 + depends: + - libblas 3.11.0 5_h4a7cf45_openblas + constrains: + - liblapacke 3.11.0 5*_openblas + - blas 2.305 openblas + - liblapack 3.11.0 5*_openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 18194 + timestamp: 1765818837135 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcblas-3.11.0-5_hd72aa62_openblas.conda + build_number: 5 + sha256: 3fad5c9de161dccb4e42c8b1ae8eccb33f4ed56bccbcced9cbb0956ae7869e61 + md5: 0b2f1143ae2d0aa4c991959d0daaf256 + depends: + - libblas 3.11.0 5_haddc8a3_openblas + constrains: + - liblapack 3.11.0 5*_openblas + - liblapacke 3.11.0 5*_openblas + - blas 2.305 openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 18371 + timestamp: 1765818618899 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.9.0-22_osx64_openblas.conda + build_number: 22 + sha256: 6a2ba9198e2320c3e22fe3d121310cf8a8ac663e94100c5693b34523fcb3cc04 + md5: b9fef82772330f61b2b0201c72d2c29b + depends: + - libblas 3.9.0 22_osx64_openblas + constrains: + - liblapacke 3.9.0 22_osx64_openblas + - blas * openblas + - liblapack 3.9.0 22_osx64_openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 14636 + timestamp: 1712542311437 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.9.0-24_osxarm64_openblas.conda + build_number: 24 + sha256: 40dc3f7c44af5cd5a2020386cb30f92943a9d8f7f54321b4d6ae32b2e54af9a4 + md5: c8977086a19233153e454bb2b332a920 + depends: + - libblas 3.9.0 24_osxarm64_openblas + constrains: + - liblapack 3.9.0 24_osxarm64_openblas + - blas * openblas + - liblapacke 3.9.0 24_osxarm64_openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 15062 + timestamp: 1726668809379 +- conda: https://conda.anaconda.org/conda-forge/win-64/libcblas-3.11.0-5_h2a3cdd5_mkl.conda + build_number: 5 + sha256: 49dc59d8e58360920314b8d276dd80da7866a1484a9abae4ee2760bc68f3e68d + md5: b3fa8e8b55310ba8ef0060103afb02b5 + depends: + - libblas 3.11.0 5_hf2e6a31_mkl + constrains: + - liblapack 3.11.0 5*_mkl + - liblapacke 3.11.0 5*_mkl + - blas 2.305 mkl + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 68079 + timestamp: 1765819124349 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libclang-cpp18.1-18.1.3-default_h7151d67_0.conda + sha256: e3b693234b50f553441795f7f7f89e4f1b1258433634f3c9988e75f30ea9e3ee + md5: 02eea994247b28cbf46b8ca52530bb39 + depends: + - libcxx >=16.0.6 + - libllvm18 >=18.1.3,<18.2.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 13694951 + timestamp: 1712568723512 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libclang-cpp18.1-18.1.3-default_he012953_0.conda + sha256: a528f933aa430c86591ed94e7eb5e4c16947232f149920250ba78e104d91e0b3 + md5: d8e0decc03dadc234e0885bb2a857c68 + depends: + - libcxx >=16.0.6 + - libllvm18 >=18.1.3,<18.2.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 12809223 + timestamp: 1712569190982 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.19.0-hcf29cc6_0.conda + sha256: a0390fd0536ebcd2244e243f5f00ab8e76ab62ed9aa214cd54470fe7496620f4 + md5: d50608c443a30c341c24277d28290f76 + depends: + - __glibc >=2.17,<3.0.a0 + - krb5 >=1.22.2,<1.23.0a0 + - libgcc >=14 + - libnghttp2 >=1.67.0,<2.0a0 + - libssh2 >=1.11.1,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.5,<4.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: curl + license_family: MIT + purls: [] + size: 466704 + timestamp: 1773218522665 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libcurl-8.19.0-hc57f145_0.conda + sha256: 75c1b2f9cff7598c593dda96c55963298bebb5bcb5a77af0b4c41cb03d26100b + md5: d5306c7ec07faf48cfb0e552c67339e0 + depends: + - krb5 >=1.22.2,<1.23.0a0 + - libgcc >=14 + - libnghttp2 >=1.67.0,<2.0a0 + - libssh2 >=1.11.1,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.5,<4.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: curl + license_family: MIT + purls: [] + size: 485694 + timestamp: 1773218484057 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libcurl-8.19.0-h8f0b9e4_0.conda + sha256: 55c6b34ae18a7f8f57d9ffe3f4ec2a82ddcc8a87248d2447f9bbba3ba66d8aec + md5: 8bc2742696d50c358f4565b25ba33b08 + depends: + - __osx >=11.0 + - krb5 >=1.22.2,<1.23.0a0 + - libnghttp2 >=1.67.0,<2.0a0 + - libssh2 >=1.11.1,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.5,<4.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: curl + license_family: MIT + purls: [] + size: 419039 + timestamp: 1773219507657 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libcurl-8.4.0-h726d00d_0.conda + sha256: cd3400ecb42fc420acb18e2d836535c44ebd501ebeb4e0bf3830776e9b4ca650 + md5: 2c17b4dedf0039736951471f493353bd + depends: + - krb5 >=1.21.2,<1.22.0a0 + - libnghttp2 >=1.52.0,<2.0a0 + - libssh2 >=1.11.0,<2.0a0 + - libzlib >=1.2.13,<2.0.0a0 + - openssl >=3.1.3,<4.0a0 + - zstd >=1.5.5,<1.6.0a0 + license: curl + license_family: MIT + purls: [] + size: 366039 + timestamp: 1697009485409 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.19.0-hd5a2499_0.conda + sha256: c4d581b067fa60f9dc0e1c5f18b756760ff094a03139e6b206eb98d185ae2bb1 + md5: 9fc7771fc8104abed9119113160be15a + depends: + - __osx >=11.0 + - krb5 >=1.22.2,<1.23.0a0 + - libnghttp2 >=1.67.0,<2.0a0 + - libssh2 >=1.11.1,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.5,<4.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: curl + license_family: MIT + purls: [] + size: 399616 + timestamp: 1773219210246 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.4.0-h2d989ff_0.conda + sha256: 5ca24ab030b1c56ce07921bf901ea99076e8b7e45586b4a04e5187cc67c87273 + md5: afabb3372209028627ec03e206f4d967 + depends: + - krb5 >=1.21.2,<1.22.0a0 + - libnghttp2 >=1.52.0,<2.0a0 + - libssh2 >=1.11.0,<2.0a0 + - libzlib >=1.2.13,<2.0.0a0 + - openssl >=3.1.3,<4.0a0 + - zstd >=1.5.5,<1.6.0a0 + license: curl + license_family: MIT + purls: [] + size: 348974 + timestamp: 1697009607821 +- conda: https://conda.anaconda.org/conda-forge/win-64/libcurl-8.19.0-h8206538_0.conda + sha256: 6b2143ba5454b399dab4471e9e1d07352a2f33b569975e6b8aedc2d9bf51cbb0 + md5: ed181e29a7ebf0f60b84b98d6140a340 + depends: + - krb5 >=1.22.2,<1.23.0a0 + - libssh2 >=1.11.1,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: curl + license_family: MIT + purls: [] + size: 392543 + timestamp: 1773218585056 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-16.0.6-hd57cbcb_0.conda + sha256: 9063271847cf05f3a6cc6cae3e7f0ced032ab5f3a3c9d3f943f876f39c5c2549 + md5: 7d6972792161077908b62971802f289a + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 1142172 + timestamp: 1686896907750 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-22.1.1-h19cb2f5_0.conda + sha256: db3adcb33eaca02311d3ba17e06c60ceaedda20240414f7b1df6e7f9ec902bfa + md5: 799141ac68a99265f04bcee196b2df51 + depends: + - __osx >=11.0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + size: 564942 + timestamp: 1773203656390 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-22.1.2-h19cb2f5_0.conda + sha256: 46561199545890e050a8a90edcfce984e5f881da86b09388926e3a6c6b759dec + md5: ed6f7b7a35f942a0301e581d72616f7d + depends: + - __osx >=11.0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 564908 + timestamp: 1774439353713 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-16.0.6-h4653b0c_0.conda + sha256: 11d3fb51c14832d9e4f6d84080a375dec21ea8a3a381a1910e67ff9cedc20355 + md5: 9d7d724faf0413bf1dbc5a85935700c8 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 1160232 + timestamp: 1686896993785 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.1-h55c6f16_0.conda + sha256: 3c8142cdd3109c250a926c492ec45bc954697b288e5d1154ada95272ffa21be8 + md5: 7a290d944bc0c481a55baf33fa289deb + depends: + - __osx >=11.0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + size: 570281 + timestamp: 1773203613980 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.2-h55c6f16_0.conda + sha256: d1402087c8792461bfc081629e8aa97e6e577a31ae0b84e6b9cc144a18f48067 + md5: 4280e0a7fd613b271e022e60dea0138c + depends: + - __osx >=11.0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 568094 + timestamp: 1774439202359 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda + sha256: d789471216e7aba3c184cd054ed61ce3f6dac6f87a50ec69291b9297f8c18724 + md5: c277e0a4d549b03ac1e9d6cbbe3d017b + depends: + - ncurses + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - ncurses >=6.5,<7.0a0 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 134676 + timestamp: 1738479519902 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libedit-3.1.20250104-pl5321h976ea20_0.conda + sha256: c0b27546aa3a23d47919226b3a1635fccdb4f24b94e72e206a751b33f46fd8d6 + md5: fb640d776fc92b682a14e001980825b1 + depends: + - ncurses + - libgcc >=13 + - ncurses >=6.5,<7.0a0 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 148125 + timestamp: 1738479808948 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libedit-3.1.20191231-h0678c8f_2.tar.bz2 + sha256: dbd3c3f2eca1d21c52e4c03b21930bbce414c4592f8ce805801575b9e9256095 + md5: 6016a8a1d0e63cac3de2c352cd40208b + depends: + - ncurses >=6.2,<7.0.0a0 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 105382 + timestamp: 1597616576726 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libedit-3.1.20250104-pl5321ha958ccf_0.conda + sha256: 6cc49785940a99e6a6b8c6edbb15f44c2dd6c789d9c283e5ee7bdfedd50b4cd6 + md5: 1f4ed31220402fcddc083b4bff406868 + depends: + - ncurses + - __osx >=10.13 + - ncurses >=6.5,<7.0a0 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 115563 + timestamp: 1738479554273 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20191231-hc8eb9b7_2.tar.bz2 + sha256: 3912636197933ecfe4692634119e8644904b41a58f30cad9d1fc02f6ba4d9fca + md5: 30e4362988a2623e9eb34337b83e01f9 + depends: + - ncurses >=6.2,<7.0.0a0 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 96607 + timestamp: 1597616630749 +- 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/libev-4.33-hd590300_2.conda + sha256: 1cd6048169fa0395af74ed5d8f1716e22c19a81a8a36f934c110ca3ad4dd27b4 + md5: 172bf1cd1ff8629f2b1179945ed45055 + depends: + - libgcc-ng >=12 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 112766 + timestamp: 1702146165126 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libev-4.33-h31becfc_2.conda + sha256: 973af77e297f1955dd1f69c2cbdc5ab9dfc88388a5576cd152cda178af0fd006 + md5: a9a13cb143bbaa477b1ebaefbe47a302 + depends: + - libgcc-ng >=12 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 115123 + timestamp: 1702146237623 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libev-4.33-h10d778d_2.conda + sha256: 0d238488564a7992942aa165ff994eca540f687753b4f0998b29b4e4d030ff43 + md5: 899db79329439820b7e8f8de41bca902 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 106663 + timestamp: 1702146352558 +- 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.4-hecca717_0.conda + sha256: d78f1d3bea8c031d2f032b760f36676d87929b18146351c4464c66b0869df3f5 + md5: e7f7ce06ec24cfcfb9e36d28cf82ba57 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + constrains: + - expat 2.7.4.* + license: MIT + license_family: MIT + purls: [] + size: 76798 + timestamp: 1771259418166 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.5-hecca717_0.conda + sha256: e8c2b57f6aacabdf2f1b0924bd4831ce5071ba080baa4a9e8c0d720588b6794c + md5: 49f570f3bc4c874a06ea69b7225753af + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + constrains: + - expat 2.7.5.* + license: MIT + license_family: MIT + purls: [] + size: 76624 + timestamp: 1774719175983 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.7.4-hfae3067_0.conda + sha256: 995ce3ad96d0f4b5ed6296b051a0d7b6377718f325bc0e792fbb96b0e369dad7 + md5: 57f3b3da02a50a1be2a6fe847515417d + depends: + - libgcc >=14 + constrains: + - expat 2.7.4.* + license: MIT + license_family: MIT + purls: [] + size: 76564 + timestamp: 1771259530958 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.7.5-hfae3067_0.conda + sha256: 6d438fc0bfdb263c24654fe49c09b31f06ec78eb709eb386392d2499af105f85 + md5: 05d1e0b30acd816a192c03dc6e164f4d + depends: + - libgcc >=14 + constrains: + - expat 2.7.5.* + license: MIT + license_family: MIT + purls: [] + size: 76523 + timestamp: 1774719129371 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.6.2-h73e2aa4_0.conda + sha256: a188a77b275d61159a32ab547f7d17892226e7dac4518d2c6ac3ac8fc8dfde92 + md5: 3d1d51c8f716d97c864d12f7af329526 + constrains: + - expat 2.6.2.* + license: MIT + license_family: MIT + purls: [] + size: 69246 + timestamp: 1710362566073 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.7.4-h991f03e_0.conda + sha256: 8d9d79b2de7d6f335692391f5281607221bf5d040e6724dad4c4d77cd603ce43 + md5: a684eb8a19b2aa68fde0267df172a1e3 + depends: + - __osx >=10.13 + constrains: + - expat 2.7.4.* + license: MIT + license_family: MIT + size: 74578 + timestamp: 1771260142624 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.7.5-hcc62823_0.conda + sha256: 341d8a457a8342c396a8ac788da2639cbc8b62568f6ba2a3d322d1ace5aa9e16 + md5: 1d6e71b8c73711e28ffe207acdc4e2f8 + depends: + - __osx >=11.0 + constrains: + - expat 2.7.5.* + license: MIT + license_family: MIT + purls: [] + size: 74797 + timestamp: 1774719557730 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.6.2-hebf3989_0.conda + sha256: ba7173ac30064ea901a4c9fb5a51846dcc25512ceb565759be7d18cbf3e5415e + md5: e3cde7cfa87f82f7cb13d482d5e0ad09 + constrains: + - expat 2.6.2.* + license: MIT + license_family: MIT + purls: [] + size: 63655 + timestamp: 1710362424980 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.7.4-hf6b4638_0.conda + sha256: 03887d8080d6a8fe02d75b80929271b39697ecca7628f0657d7afaea87761edf + md5: a92e310ae8dfc206ff449f362fc4217f + depends: + - __osx >=11.0 + constrains: + - expat 2.7.4.* + license: MIT + license_family: MIT + size: 68199 + timestamp: 1771260020767 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.7.5-hf6b4638_0.conda + sha256: 06780dec91dd25770c8cf01e158e1062fbf7c576b1406427475ce69a8af75b7e + md5: a32123f93e168eaa4080d87b0fb5da8a + depends: + - __osx >=11.0 + constrains: + - expat 2.7.5.* + license: MIT + license_family: MIT + purls: [] + size: 68192 + timestamp: 1774719211725 +- conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.7.4-hac47afa_0.conda + sha256: b31f6fb629c4e17885aaf2082fb30384156d16b48b264e454de4a06a313b533d + md5: 1c1ced969021592407f16ada4573586d + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + constrains: + - expat 2.7.4.* + license: MIT + license_family: MIT + purls: [] + size: 70323 + timestamp: 1771259521393 +- conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.7.5-hac47afa_0.conda + sha256: 6850c3a4d5dc215b86f58518cfb8752998533d6569b08da8df1da72e7c68e571 + md5: bfb43f52f13b7c56e7677aa7a8efdf0c + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + constrains: + - expat 2.7.5.* + license: MIT + license_family: MIT + purls: [] + size: 70609 + timestamp: 1774719377850 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda + sha256: 31f19b6a88ce40ebc0d5a992c131f57d919f73c0b92cd1617a5bec83f6e961e6 + md5: a360c33a5abe61c07959e449fa1453eb + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: MIT + license_family: MIT + purls: [] + size: 58592 + timestamp: 1769456073053 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda + sha256: 3df4c539449aabc3443bbe8c492c01d401eea894603087fca2917aa4e1c2dea9 + md5: 2f364feefb6a7c00423e80dcb12db62a + depends: + - libgcc >=14 + license: MIT + license_family: MIT + purls: [] + size: 55952 + timestamp: 1769456078358 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.4.2-h0d85af4_5.tar.bz2 + sha256: 7a2d27a936ceee6942ea4d397f9c7d136f12549d86f7617e8b6bad51e01a941f + md5: ccb34fb14960ad8b125962d3d79b31a9 + license: MIT + license_family: MIT + purls: [] + size: 51348 + timestamp: 1636488394370 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.5.2-hd1f9c09_0.conda + sha256: 951958d1792238006fdc6fce7f71f1b559534743b26cc1333497d46e5903a2d6 + md5: 66a0dc7464927d0853b590b6f53ba3ea + depends: + - __osx >=10.13 + license: MIT + license_family: MIT + purls: [] + size: 53583 + timestamp: 1769456300951 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.2-h3422bc3_5.tar.bz2 + sha256: 41b3d13efb775e340e4dba549ab5c029611ea6918703096b2eaa9c015c0750ca + md5: 086914b672be056eb70fd4285b6783b6 + license: MIT + license_family: MIT + purls: [] + size: 39020 + timestamp: 1636488587153 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_0.conda + sha256: 6686a26466a527585e6a75cc2a242bf4a3d97d6d6c86424a441677917f28bec7 + md5: 43c04d9cb46ef176bb2a4c77e324d599 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 40979 + timestamp: 1769456747661 +- conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.5.2-h3d046cb_0.conda + sha256: 59d01f2dfa8b77491b5888a5ab88ff4e1574c9359f7e229da254cdfe27ddc190 + md5: 720b39f5ec0610457b725eb3f396219a + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: MIT + license_family: MIT + purls: [] + size: 45831 + timestamp: 1769456418774 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda + sha256: faf7d2017b4d718951e3a59d081eb09759152f93038479b768e3d612688f83f5 + md5: 0aa00f03f9e39fb9876085dee11a85d4 + depends: + - __glibc >=2.17,<3.0.a0 + - _openmp_mutex >=4.5 + constrains: + - libgcc-ng ==15.2.0=*_18 + - libgomp 15.2.0 he0feb66_18 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 1041788 + timestamp: 1771378212382 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_18.conda + sha256: 43df385bedc1cab11993c4369e1f3b04b4ca5d0ea16cba6a0e7f18dbc129fcc9 + md5: 552567ea2b61e3a3035759b2fdb3f9a6 + depends: + - _openmp_mutex >=4.5 + constrains: + - libgcc-ng ==15.2.0=*_18 + - libgomp 15.2.0 h8acb6b2_18 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 622900 + timestamp: 1771378128706 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libgcc-15.2.0-h08519bb_18.conda + sha256: 83366f11615ab234aa1e0797393f9e07b78124b5a24c4a9f8af0113d02df818e + md5: 9a5cb96e43f5c2296690186e15b3296f + depends: + - _openmp_mutex + constrains: + - libgcc-ng ==15.2.0=*_18 + - libgomp 15.2.0 18 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 423025 + timestamp: 1771378225170 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-15.2.0-hcbb3090_18.conda + sha256: 1d9c4f35586adb71bcd23e31b68b7f3e4c4ab89914c26bed5f2859290be5560e + md5: 92df6107310b1fff92c4cc84f0de247b + depends: + - _openmp_mutex + constrains: + - libgcc-ng ==15.2.0=*_18 + - libgomp 15.2.0 18 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 401974 + timestamp: 1771378877463 +- conda: https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_linux-64-14.3.0-hf649bbc_118.conda + sha256: 1abc6a81ee66e8ac9ac09a26e2d6ad7bba23f0a0cc3a6118654f036f9c0e1854 + md5: 06901733131833f5edd68cf3d9679798 + depends: + - __unix + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 3084533 + timestamp: 1771377786730 +- conda: https://conda.anaconda.org/conda-forge/noarch/libgcc-devel_linux-aarch64-14.3.0-h25ba3ff_118.conda + sha256: 058fab0156cb13897f7e4a2fc9d63c922d3de09b6429390365f91b62f1dddb0e + md5: 3733752e5a7a0737c8c4f1897f2074f9 + depends: + - __unix + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 2335839 + timestamp: 1771377646960 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda + sha256: e318a711400f536c81123e753d4c797a821021fb38970cebfb3f454126016893 + md5: d5e96b1ed75ca01906b3d2469b4ce493 + depends: + - libgcc 15.2.0 he0feb66_18 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 27526 + timestamp: 1771378224552 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-ng-15.2.0-he9431aa_18.conda + sha256: 83bb0415f59634dccfa8335d4163d1f6db00a27b36666736f9842b650b92cf2f + md5: 4feebd0fbf61075a1a9c2e9b3936c257 + depends: + - libgcc 15.2.0 h8acb6b2_18 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 27568 + timestamp: 1771378136019 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_18.conda + sha256: d2c9fad338fd85e4487424865da8e74006ab2e2475bd788f624d7a39b2a72aee + md5: 9063115da5bc35fdc3e1002e69b9ef6e + depends: + - libgfortran5 15.2.0 h68bc16d_18 + constrains: + - libgfortran-ng ==15.2.0=*_18 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 27523 + timestamp: 1771378269450 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran-15.2.0-he9431aa_18.conda + sha256: 7dcd7dff2505d56fd5272a6e712ec912f50a46bf07dc6873a7e853694304e6e4 + md5: 41f261f5e4e2e8cbd236c2f1f15dae1b + depends: + - libgfortran5 15.2.0 h1b7bec0_18 + constrains: + - libgfortran-ng ==15.2.0=*_18 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 27587 + timestamp: 1771378169244 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.2.0-h7e5c614_18.conda + sha256: fb06c2a2ef06716a0f2a6550f5d13cdd1d89365993068512b7ae3c34e6e665d9 + md5: 34a9f67498721abcfef00178bcf4b190 + depends: + - libgfortran5 15.2.0 hd16e46c_18 + constrains: + - libgfortran-ng ==15.2.0=*_18 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 139761 + timestamp: 1771378423828 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.2.0-h07b0088_18.conda + sha256: 63f89087c3f0c8621c5c89ecceec1e56e5e1c84f65fc9c5feca33a07c570a836 + md5: 26981599908ed2205366e8fc91b37fc6 + depends: + - libgfortran5 15.2.0 hdae7583_18 + constrains: + - libgfortran-ng ==15.2.0=*_18 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 138973 + timestamp: 1771379054939 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_18.conda + sha256: 539b57cf50ec85509a94ba9949b7e30717839e4d694bc94f30d41c9d34de2d12 + md5: 646855f357199a12f02a87382d429b75 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=15.2.0 + constrains: + - libgfortran 15.2.0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 2482475 + timestamp: 1771378241063 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgfortran5-15.2.0-h1b7bec0_18.conda + sha256: 85347670dfb4a8d4c13cd7cae54138dcf2b1606b6bede42eef5507bf5f9660c6 + md5: 574d88ce3348331e962cfa5ed451b247 + depends: + - libgcc >=15.2.0 + constrains: + - libgfortran 15.2.0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 1486341 + timestamp: 1771378148102 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.2.0-hd16e46c_18.conda + sha256: ddaf9dcf008c031b10987991aa78643e03c24a534ad420925cbd5851b31faa11 + md5: ca52daf58cea766656266c8771d8be81 + depends: + - libgcc >=15.2.0 + constrains: + - libgfortran 15.2.0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 1062274 + timestamp: 1771378232014 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.2.0-hdae7583_18.conda + sha256: 91033978ba25e6a60fb86843cf7e1f7dc8ad513f9689f991c9ddabfaf0361e7e + md5: c4a6f7989cffb0544bfd9207b6789971 + depends: + - libgcc >=15.2.0 + constrains: + - libgfortran 15.2.0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 598634 + timestamp: 1771378886363 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda + sha256: 21337ab58e5e0649d869ab168d4e609b033509de22521de1bfed0c031bfc5110 + md5: 239c5e9546c38a1e884d69effcf4c882 + depends: + - __glibc >=2.17,<3.0.a0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 603262 + timestamp: 1771378117851 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_18.conda + sha256: fc716f11a6a8525e27a5d332ef6a689210b0d2a4dd1133edc0f530659aa9faa6 + md5: 4faa39bf919939602e594253bd673958 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 588060 + timestamp: 1771378040807 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.13.0-default_he001693_1000.conda + sha256: 5041d295813dfb84652557839825880aae296222ab725972285c5abe3b6e4288 + md5: c197985b58bc813d26b42881f0021c82 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + - libxml2 + - libxml2-16 >=2.14.6 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 2436378 + timestamp: 1770953868164 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libhwloc-2.13.0-default_ha95e27d_1000.conda + sha256: 88888d99e81c93e7331f2eb0fec08b3c4a47a1bfa1c88b3e641f6568569b6261 + md5: 974183f6420938051e2f3208922d057f + depends: + - libgcc >=14 + - libstdcxx >=14 + - libxml2 + - libxml2-16 >=2.14.6 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 2453519 + timestamp: 1770953713701 +- conda: https://conda.anaconda.org/conda-forge/win-64/libhwloc-2.12.2-default_h4379cf1_1000.conda + sha256: 8cdf11333a81085468d9aa536ebb155abd74adc293576f6013fc0c85a7a90da3 + md5: 3b576f6860f838f950c570f4433b086e + depends: + - libwinpthread >=12.0.0.r4.gg4f2fc60ca + - libxml2 + - libxml2-16 >=2.14.6 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 2411241 + timestamp: 1765104337762 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda + sha256: c467851a7312765447155e071752d7bf9bf44d610a5687e32706f480aad2833f + md5: 915f5995e94f60e9a4826e0b0920ee88 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: LGPL-2.1-only + purls: [] + size: 790176 + timestamp: 1754908768807 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libiconv-1.18-h90929bb_2.conda + sha256: 1473451cd282b48d24515795a595801c9b65b567fe399d7e12d50b2d6cdb04d9 + md5: 5a86bf847b9b926f3a4f203339748d78 + depends: + - libgcc >=14 + license: LGPL-2.1-only + purls: [] + size: 791226 + timestamp: 1754910975665 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.17-hd75f5a5_2.conda + sha256: 23d4923baeca359423a7347c2ed7aaf48c68603df0cf8b87cc94a10b0d4e9a23 + md5: 6c3628d047e151efba7cf08c5e54d1ca + license: LGPL-2.1-only + purls: [] + size: 666538 + timestamp: 1702682713201 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.18-h57a12c2_2.conda + sha256: a1c8cecdf9966921e13f0ae921309a1f415dfbd2b791f2117cf7e8f5e61a48b6 + md5: 210a85a1119f97ea7887188d176db135 + depends: + - __osx >=10.13 + license: LGPL-2.1-only + purls: [] + size: 737846 + timestamp: 1754908900138 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.17-h0d3ecfb_2.conda + sha256: bc7de5097b97bcafcf7deaaed505f7ce02f648aac8eccc0d5a47cc599a1d0304 + md5: 69bda57310071cf6d2b86caf11573d2d + license: LGPL-2.1-only + purls: [] + size: 676469 + timestamp: 1702682458114 +- 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/win-64/libiconv-1.18-hc1393d2_2.conda + sha256: 0dcdb1a5f01863ac4e8ba006a8b0dc1a02d2221ec3319b5915a1863254d7efa7 + md5: 64571d1dd6cdcfa25d0664a5950fdaa2 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: LGPL-2.1-only + purls: [] + size: 696926 + timestamp: 1754909290005 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-5_h47877c9_openblas.conda + build_number: 5 + sha256: c723b6599fcd4c6c75dee728359ef418307280fa3e2ee376e14e85e5bbdda053 + md5: b38076eb5c8e40d0106beda6f95d7609 + depends: + - libblas 3.11.0 5_h4a7cf45_openblas + constrains: + - blas 2.305 openblas + - liblapacke 3.11.0 5*_openblas + - libcblas 3.11.0 5*_openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 18200 + timestamp: 1765818857876 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblapack-3.11.0-5_h88aeb00_openblas.conda + build_number: 5 + sha256: 692222d186d3ffbc99eaf04b5b20181fd26aee1edec1106435a0a755c57cce86 + md5: 88d1e4133d1182522b403e9ba7435f04 + depends: + - libblas 3.11.0 5_haddc8a3_openblas + constrains: + - liblapacke 3.11.0 5*_openblas + - blas 2.305 openblas + - libcblas 3.11.0 5*_openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 18392 + timestamp: 1765818627104 +- conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.9.0-22_osx64_openblas.conda + build_number: 22 + sha256: e36744f3e780564d6748b5dd05e15ad6a1af9184cf32ab9d1304c13a6bc3e16b + md5: f21b282ff7ba14df6134a0fe6ab42b1b + depends: + - libblas 3.9.0 22_osx64_openblas + constrains: + - liblapacke 3.9.0 22_osx64_openblas + - blas * openblas + - libcblas 3.9.0 22_osx64_openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 14657 + timestamp: 1712542322711 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.9.0-24_osxarm64_openblas.conda + build_number: 24 + sha256: 67fbfd0466eee443cda9596ed22daabedc96b7b4d1b31f49b1c1b0983dd1dd2c + md5: 49a3241f76cdbe705e346204a328f66c + depends: + - libblas 3.9.0 24_osxarm64_openblas + constrains: + - blas * openblas + - liblapacke 3.9.0 24_osxarm64_openblas + - libcblas 3.9.0 24_osxarm64_openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 15063 + timestamp: 1726668815824 +- conda: https://conda.anaconda.org/conda-forge/win-64/liblapack-3.11.0-5_hf9ab0e9_mkl.conda + build_number: 5 + sha256: a2d33f5cc2b8a9042f2af6981c6733ab1a661463823eaa56595a9c58c0ab77e1 + md5: e62c42a4196dee97d20400612afcb2b1 + depends: + - libblas 3.11.0 5_hf2e6a31_mkl + constrains: + - libcblas 3.11.0 5*_mkl + - blas 2.305 mkl + - liblapacke 3.11.0 5*_mkl + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 80225 + timestamp: 1765819148014 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libllvm18-18.1.3-hbcf5fad_0.conda + sha256: bc42a9999c8846f50f5b3bb9a2338caeab34f2d7de8202e3fad7f929f38e3287 + md5: f286e87d892273a1ef3059744c833f91 + depends: + - libcxx >=16 + - libxml2 >=2.12.6,<2.14.0a0 + - libzlib >=1.2.13,<2.0.0a0 + - zstd >=1.5.5,<1.6.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 27580830 + timestamp: 1712517566570 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libllvm18-18.1.3-h30cc82d_0.conda + sha256: 5a8781ab13b163fd028916d050bb209718b14de85493bb7a4b93ea798998b9fe + md5: fad73e8421bcd0de381d172c2224d3a5 + depends: + - libcxx >=16 + - libxml2 >=2.12.6,<2.14.0a0 + - libzlib >=1.2.13,<2.0.0a0 + - zstd >=1.5.5,<1.6.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 25782519 + timestamp: 1712517407600 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda + sha256: 755c55ebab181d678c12e49cced893598f2bab22d582fbbf4d8b83c18be207eb + md5: c7c83eecbb72d88b940c249af56c8b17 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + constrains: + - xz 5.8.2.* + license: 0BSD + purls: [] + size: 113207 + timestamp: 1768752626120 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.2-he30d5cf_0.conda + sha256: 843c46e20519651a3e357a8928352b16c5b94f4cd3d5481acc48be2e93e8f6a3 + md5: 96944e3c92386a12755b94619bae0b35 + depends: + - libgcc >=14 + constrains: + - xz 5.8.2.* + license: 0BSD + purls: [] + size: 125916 + timestamp: 1768754941722 +- conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.2-h11316ed_0.conda + sha256: 7ab3c98abd3b5d5ec72faa8d9f5d4b50dcee4970ed05339bc381861199dabb41 + md5: 688a0c3d57fa118b9c97bf7e471ab46c + depends: + - __osx >=10.13 + constrains: + - xz 5.8.2.* + license: 0BSD + purls: [] + size: 105482 + timestamp: 1768753411348 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.2-h8088a28_0.conda + sha256: 7bfc7ffb2d6a9629357a70d4eadeadb6f88fa26ebc28f606b1c1e5e5ed99dc7e + md5: 009f0d956d7bfb00de86901d16e486c7 + depends: + - __osx >=11.0 + constrains: + - xz 5.8.2.* + license: 0BSD + purls: [] + size: 92242 + timestamp: 1768752982486 +- conda: https://conda.anaconda.org/conda-forge/win-64/liblzma-5.8.2-hfd05255_0.conda + sha256: f25bf293f550c8ed2e0c7145eb404324611cfccff37660869d97abf526eb957c + md5: ba0bfd4c3cf73f299ffe46ff0eaeb8e3 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + constrains: + - xz 5.8.2.* + license: 0BSD + purls: [] + size: 106169 + timestamp: 1768752763559 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-2.5.0-hd28c85e_0.conda + sha256: ca2d384f30e1582b7c6ae9f1406fb51f993e44c92799e3cabf2130f69c7261d5 + md5: a24532d0660b8a58ca2955301281f71e + depends: + - cpp-expected >=1.3.1,<1.3.2.0a0 + - __glibc >=2.17,<3.0.a0 + - libstdcxx >=14 + - libgcc >=14 + - zstd >=1.5.7,<1.6.0a0 + - reproc >=14.2,<15.0a0 + - spdlog >=1.17.0,<1.18.0a0 + - libarchive >=3.8.5,<3.9.0a0 + - openssl >=3.5.4,<4.0a0 + - nlohmann_json-abi ==3.12.0 + - fmt >=12.1.0,<12.2.0a0 + - simdjson >=4.2.4,<4.3.0a0 + - libsolv >=0.7.35,<0.8.0a0 + - reproc-cpp >=14.2,<15.0a0 + - libcurl >=8.18.0,<9.0a0 + - yaml-cpp >=0.8.0,<0.9.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 2567543 + timestamp: 1767884157869 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmamba-2.5.0-hc712cdd_0.conda + sha256: 480913318158db625ca7862a2447eda8aa84c8a315d4f86cc1764a5f1050e61c + md5: 45c3a33d8c6db2382678b3c90af03dd4 + depends: + - cpp-expected >=1.3.1,<1.3.2.0a0 + - libstdcxx >=14 + - libgcc >=14 + - nlohmann_json-abi ==3.12.0 + - zstd >=1.5.7,<1.6.0a0 + - libsolv >=0.7.35,<0.8.0a0 + - yaml-cpp >=0.8.0,<0.9.0a0 + - reproc-cpp >=14.2,<15.0a0 + - fmt >=12.1.0,<12.2.0a0 + - spdlog >=1.17.0,<1.18.0a0 + - reproc >=14.2,<15.0a0 + - openssl >=3.5.4,<4.0a0 + - simdjson >=4.2.4,<4.3.0a0 + - libarchive >=3.8.5,<3.9.0a0 + - libcurl >=8.18.0,<9.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 2414027 + timestamp: 1767884182395 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libmamba-2.5.0-h7fe6c55_0.conda + sha256: 614dc840d50442e8732e7373821ca5802626bd9b0654491a135e6cf3dbbbb428 + md5: bcc1e88e0437b6a0a5fb5bab84b7b995 + depends: + - cpp-expected >=1.3.1,<1.3.2.0a0 + - __osx >=10.13 + - libcxx >=19 + - simdjson >=4.2.4,<4.3.0a0 + - reproc >=14.2,<15.0a0 + - libarchive >=3.8.5,<3.9.0a0 + - yaml-cpp >=0.8.0,<0.9.0a0 + - spdlog >=1.17.0,<1.18.0a0 + - nlohmann_json-abi ==3.12.0 + - zstd >=1.5.7,<1.6.0a0 + - reproc-cpp >=14.2,<15.0a0 + - openssl >=3.5.4,<4.0a0 + - libcurl >=8.18.0,<9.0a0 + - fmt >=12.1.0,<12.2.0a0 + - libsolv >=0.7.35,<0.8.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 1785898 + timestamp: 1767884200743 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmamba-2.5.0-h7950639_0.conda + sha256: 78fccef61fe4d6763c60e19dd5bc8aad7db553188609e3bd91159d158aecabaa + md5: 29e8e662089a1226a90a5dc5d499b7b7 + depends: + - cpp-expected >=1.3.1,<1.3.2.0a0 + - libcxx >=19 + - __osx >=11.0 + - zstd >=1.5.7,<1.6.0a0 + - reproc >=14.2,<15.0a0 + - libsolv >=0.7.35,<0.8.0a0 + - fmt >=12.1.0,<12.2.0a0 + - yaml-cpp >=0.8.0,<0.9.0a0 + - libarchive >=3.8.5,<3.9.0a0 + - nlohmann_json-abi ==3.12.0 + - spdlog >=1.17.0,<1.18.0a0 + - simdjson >=4.2.4,<4.3.0a0 + - libcurl >=8.18.0,<9.0a0 + - openssl >=3.5.4,<4.0a0 + - reproc-cpp >=14.2,<15.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 1653523 + timestamp: 1767884201469 +- conda: https://conda.anaconda.org/conda-forge/win-64/libmamba-2.5.0-h06825f5_0.conda + sha256: 632acf45a127242ca0dddc942c635bd43de718c51477ac000ed579410b7363a3 + md5: df96c0c3390a753e0c2df57fdbf98d97 + depends: + - cpp-expected >=1.3.1,<1.3.2.0a0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - libarchive >=3.8.5,<3.9.0a0 + - libcurl >=8.18.0,<9.0a0 + - spdlog >=1.17.0,<1.18.0a0 + - zstd >=1.5.7,<1.6.0a0 + - yaml-cpp >=0.8.0,<0.9.0a0 + - reproc >=14.2,<15.0a0 + - fmt >=12.1.0,<12.2.0a0 + - nlohmann_json-abi ==3.12.0 + - libsolv >=0.7.35,<0.8.0a0 + - simdjson >=4.2.4,<4.3.0a0 + - openssl >=3.5.4,<4.0a0 + - reproc-cpp >=14.2,<15.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 4995231 + timestamp: 1767884194847 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmamba-spdlog-2.5.0-h12fcf84_0.conda + sha256: 75deca8004690aed0985845f734927e48aa49a683ee09b3d9ff4e22ace9e4a8e + md5: c866cdca3b16b5c7a0fd9916d5d64577 + depends: + - libstdcxx >=14 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - libmamba >=2.5.0,<2.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 20396 + timestamp: 1767884157870 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmamba-spdlog-2.5.0-h3ad78e7_0.conda + sha256: d100a04349427cfb8cc76b4c0736bd27fd77ccb9c07e8a25e9988cbf718c610b + md5: 4abcea9b345dd46ecc86ca7c20f3db62 + depends: + - libstdcxx >=14 + - libgcc >=14 + - libmamba >=2.5.0,<2.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 23017 + timestamp: 1767884182397 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libmamba-spdlog-2.5.0-hb923e0c_0.conda + sha256: 3bc7cdc7d617a62b86df95cb198614794a533edc360d47b5116a9295215e6955 + md5: 7e25602d391cbdba87191a231594058d + depends: + - libcxx >=19 + - __osx >=10.13 + - libmamba >=2.5.0,<2.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 20784 + timestamp: 1767884200753 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmamba-spdlog-2.5.0-h85b9800_0.conda + sha256: c0efbd9cf938a44fe98cfeb77d9bbb119f58bf0202ec5009b7d6621c6b96721c + md5: 6a3a2f6d6e90363288a96bc355b417c2 + depends: + - libcxx >=19 + - __osx >=11.0 + - libmamba >=2.5.0,<2.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 23068 + timestamp: 1767884201476 +- conda: https://conda.anaconda.org/conda-forge/win-64/libmamba-spdlog-2.5.0-h9ae1bf1_0.conda + sha256: 172991ecd8ffe8aadff9f083b8c1de282d91e670c939cdfff5970ccacbe98548 + md5: 463b59502db7115998f7d537ccd932df + depends: + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - libmamba >=2.5.0,<2.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 18007 + timestamp: 1767884194852 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.5.0-py310h74f1d5f_0.conda + sha256: a949389f9c3196fed8377a47ee266546f3e35d6d237f8209d3bb77ffc104c748 + md5: edd4cf55ce1926c90c5702ba24b3fc08 + depends: + - python + - libmamba ==2.5.0 hd28c85e_0 + - libmamba-spdlog ==2.5.0 h12fcf84_0 + - libstdcxx >=14 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - libmamba >=2.5.0,<2.6.0a0 + - openssl >=3.5.4,<4.0a0 + - nlohmann_json-abi ==3.12.0 + - zstd >=1.5.7,<1.6.0a0 + - spdlog >=1.17.0,<1.18.0a0 + - pybind11-abi ==11 + - python_abi 3.10.* *_cp310 + - fmt >=12.1.0,<12.2.0a0 + - yaml-cpp >=0.8.0,<0.9.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/libmambapy?source=hash-mapping + size: 943029 + timestamp: 1767884157872 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.5.0-py311hc5d5c7c_0.conda + sha256: ebd16f6685bdc2f0cf595f0f441b638b378a43e76e2124763c35d548df09084b + md5: f72a2daebdd84c968828602bfa081ae5 + depends: + - python + - libmamba ==2.5.0 hd28c85e_0 + - libmamba-spdlog ==2.5.0 h12fcf84_0 + - __glibc >=2.17,<3.0.a0 + - libstdcxx >=14 + - libgcc >=14 + - zstd >=1.5.7,<1.6.0a0 + - fmt >=12.1.0,<12.2.0a0 + - python_abi 3.11.* *_cp311 + - openssl >=3.5.4,<4.0a0 + - yaml-cpp >=0.8.0,<0.9.0a0 + - spdlog >=1.17.0,<1.18.0a0 + - nlohmann_json-abi ==3.12.0 + - pybind11-abi ==11 + - libmamba >=2.5.0,<2.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/libmambapy?source=hash-mapping + size: 944797 + timestamp: 1767884157872 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmambapy-2.5.0-py314hcbd71af_0.conda + sha256: 578a2ec09095c81674af0fa88ee44083c3a4ab10c31b498ddfa519fc9ff855b1 + md5: 54125b30d5031808bca8018561843f40 + depends: + - python + - libmamba ==2.5.0 hd28c85e_0 + - libmamba-spdlog ==2.5.0 h12fcf84_0 + - libstdcxx >=14 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - zstd >=1.5.7,<1.6.0a0 + - python_abi 3.14.* *_cp314 + - pybind11-abi ==11 + - fmt >=12.1.0,<12.2.0a0 + - nlohmann_json-abi ==3.12.0 + - spdlog >=1.17.0,<1.18.0a0 + - openssl >=3.5.4,<4.0a0 + - yaml-cpp >=0.8.0,<0.9.0a0 + - libmamba >=2.5.0,<2.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/libmambapy?source=hash-mapping + size: 948138 + timestamp: 1767884157875 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmambapy-2.5.0-py310hdf79504_0.conda + sha256: 48fe0ec831974af7f660bfe8e8bfbf5a1a4a2fed125496b1ee53fd83c40a5027 + md5: 59097ccbbc66568039aa714f48f77700 + depends: + - python + - libmamba ==2.5.0 hc712cdd_0 + - libmamba-spdlog ==2.5.0 h3ad78e7_0 + - libstdcxx >=14 + - libgcc >=14 + - python 3.10.* *_cpython + - zstd >=1.5.7,<1.6.0a0 + - pybind11-abi ==11 + - spdlog >=1.17.0,<1.18.0a0 + - yaml-cpp >=0.8.0,<0.9.0a0 + - fmt >=12.1.0,<12.2.0a0 + - nlohmann_json-abi ==3.12.0 + - openssl >=3.5.4,<4.0a0 + - python_abi 3.10.* *_cp310 + - libmamba >=2.5.0,<2.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/libmambapy?source=hash-mapping + size: 832789 + timestamp: 1767884182399 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmambapy-2.5.0-py311h6a8bf82_0.conda + sha256: caef2c6e32e15afc8bb1cf66151223738a29d45cf639acad0267bce948518cc7 + md5: e022e9542b664361fcbc1f9c5528a0a8 + depends: + - python + - libmamba ==2.5.0 hc712cdd_0 + - libmamba-spdlog ==2.5.0 h3ad78e7_0 + - python 3.11.* *_cpython + - libstdcxx >=14 + - libgcc >=14 + - nlohmann_json-abi ==3.12.0 + - fmt >=12.1.0,<12.2.0a0 + - libmamba >=2.5.0,<2.6.0a0 + - python_abi 3.11.* *_cp311 + - zstd >=1.5.7,<1.6.0a0 + - pybind11-abi ==11 + - openssl >=3.5.4,<4.0a0 + - yaml-cpp >=0.8.0,<0.9.0a0 + - spdlog >=1.17.0,<1.18.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/libmambapy?source=hash-mapping + size: 832040 + timestamp: 1767884182400 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmambapy-2.5.0-py314h709e558_0.conda + sha256: c226d92922115e9e4a0097b15521b0238a69a028ed0d525f5a5ed6696314ed69 + md5: b9108a7151ea087a321b7ebe3aaba999 + depends: + - python + - libmamba ==2.5.0 hc712cdd_0 + - libmamba-spdlog ==2.5.0 h3ad78e7_0 + - python 3.14.* *_cp314 + - libstdcxx >=14 + - libgcc >=14 + - fmt >=12.1.0,<12.2.0a0 + - spdlog >=1.17.0,<1.18.0a0 + - python_abi 3.14.* *_cp314 + - zstd >=1.5.7,<1.6.0a0 + - yaml-cpp >=0.8.0,<0.9.0a0 + - libmamba >=2.5.0,<2.6.0a0 + - pybind11-abi ==11 + - openssl >=3.5.4,<4.0a0 + - nlohmann_json-abi ==3.12.0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/libmambapy?source=hash-mapping + size: 834849 + timestamp: 1767884182402 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libmambapy-2.5.0-py314haca2e77_0.conda + sha256: a3dad1d241d2fd1831dd4e8893ecdd4e4daa1cba4f1c3d8b630d5f4cd5a1279d + md5: a015fcf12fbe739adfae4cb32f627da6 + depends: + - python + - libmamba ==2.5.0 h7fe6c55_0 + - libmamba-spdlog ==2.5.0 hb923e0c_0 + - __osx >=10.13 + - libcxx >=19 + - fmt >=12.1.0,<12.2.0a0 + - pybind11-abi ==11 + - libmamba >=2.5.0,<2.6.0a0 + - yaml-cpp >=0.8.0,<0.9.0a0 + - python_abi 3.14.* *_cp314 + - zstd >=1.5.7,<1.6.0a0 + - spdlog >=1.17.0,<1.18.0a0 + - nlohmann_json-abi ==3.12.0 + - openssl >=3.5.4,<4.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/libmambapy?source=hash-mapping + size: 815795 + timestamp: 1767884200763 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmambapy-2.5.0-py314hf8f60b7_0.conda + sha256: 11824fa9b721afe43cfd83ba899c893c1dba0b42c85ec618aa9284fd2ad66d6c + md5: c215957a49ac69b30d94a39eb1182009 + depends: + - python + - libmamba ==2.5.0 h7950639_0 + - libmamba-spdlog ==2.5.0 h85b9800_0 + - __osx >=11.0 + - python 3.14.* *_cp314 + - libcxx >=19 + - yaml-cpp >=0.8.0,<0.9.0a0 + - libmamba >=2.5.0,<2.6.0a0 + - zstd >=1.5.7,<1.6.0a0 + - spdlog >=1.17.0,<1.18.0a0 + - nlohmann_json-abi ==3.12.0 + - python_abi 3.14.* *_cp314 + - openssl >=3.5.4,<4.0a0 + - fmt >=12.1.0,<12.2.0a0 + - pybind11-abi ==11 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/libmambapy?source=hash-mapping + size: 769644 + timestamp: 1767884201481 +- conda: https://conda.anaconda.org/conda-forge/win-64/libmambapy-2.5.0-py310h1916185_0.conda + sha256: c62cb131596e5aaba82591a5c76081d06b6b4dde5af25c25cbd796efc0458fab + md5: 4c67f7b1103f72faa72a50f79587990b + depends: + - python + - libmamba ==2.5.0 h06825f5_0 + - libmamba-spdlog ==2.5.0 h9ae1bf1_0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - spdlog >=1.17.0,<1.18.0a0 + - python_abi 3.10.* *_cp310 + - fmt >=12.1.0,<12.2.0a0 + - nlohmann_json-abi ==3.12.0 + - openssl >=3.5.4,<4.0a0 + - yaml-cpp >=0.8.0,<0.9.0a0 + - libmamba >=2.5.0,<2.6.0a0 + - zstd >=1.5.7,<1.6.0a0 + - pybind11-abi ==11 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/libmambapy?source=hash-mapping + size: 583910 + timestamp: 1767884194854 +- conda: https://conda.anaconda.org/conda-forge/win-64/libmambapy-2.5.0-py311hb0041a4_0.conda + sha256: d3ec31a3cfb43b07d04899cfd84376a31049be9611ab249b4889f0672e6d81b9 + md5: 2b522dd15f2449d921759864fd0648aa + depends: + - python + - libmamba ==2.5.0 h06825f5_0 + - libmamba-spdlog ==2.5.0 h9ae1bf1_0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - nlohmann_json-abi ==3.12.0 + - openssl >=3.5.4,<4.0a0 + - python_abi 3.11.* *_cp311 + - zstd >=1.5.7,<1.6.0a0 + - libmamba >=2.5.0,<2.6.0a0 + - fmt >=12.1.0,<12.2.0a0 + - pybind11-abi ==11 + - yaml-cpp >=0.8.0,<0.9.0a0 + - spdlog >=1.17.0,<1.18.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/libmambapy?source=hash-mapping + size: 583683 + timestamp: 1767884194856 +- conda: https://conda.anaconda.org/conda-forge/win-64/libmambapy-2.5.0-py314h532c739_0.conda + sha256: 3b5bec6472c07448e8485def16a11157c32295e9016130809fc4b3b1e6dda174 + md5: c9cd67775b772d64b54239fefb4d8504 + depends: + - python + - libmamba ==2.5.0 h06825f5_0 + - libmamba-spdlog ==2.5.0 h9ae1bf1_0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - fmt >=12.1.0,<12.2.0a0 + - zstd >=1.5.7,<1.6.0a0 + - yaml-cpp >=0.8.0,<0.9.0a0 + - nlohmann_json-abi ==3.12.0 + - spdlog >=1.17.0,<1.18.0a0 + - pybind11-abi ==11 + - libmamba >=2.5.0,<2.6.0a0 + - python_abi 3.14.* *_cp314 + - openssl >=3.5.4,<4.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/libmambapy?source=hash-mapping + size: 587744 + timestamp: 1767884194858 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda + sha256: fe171ed5cf5959993d43ff72de7596e8ac2853e9021dec0344e583734f1e0843 + md5: 2c21e66f50753a083cbe6b80f38268fa + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 92400 + timestamp: 1769482286018 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmpdec-4.0.0-he30d5cf_1.conda + sha256: 57c0dd12d506e84541c4e877898bd2a59cca141df493d34036f18b2751e0a453 + md5: 7b9813e885482e3ccb1fa212b86d7fd0 + depends: + - libgcc >=14 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 114056 + timestamp: 1769482343003 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libmpdec-4.0.0-hf3981d6_1.conda + sha256: 1096c740109386607938ab9f09a7e9bca06d86770a284777586d6c378b8fb3fd + md5: ec88ba8a245855935b871a7324373105 + depends: + - __osx >=10.13 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 79899 + timestamp: 1769482558610 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_1.conda + sha256: 1089c7f15d5b62c622625ec6700732ece83be8b705da8c6607f4dabb0c4bd6d2 + md5: 57c4be259f5e0b99a5983799a228ae55 + depends: + - __osx >=11.0 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 73690 + timestamp: 1769482560514 +- conda: https://conda.anaconda.org/conda-forge/win-64/libmpdec-4.0.0-hfd05255_1.conda + sha256: 40dcd0b9522a6e0af72a9db0ced619176e7cfdb114855c7a64f278e73f8a7514 + md5: e4a9fc2bba3b022dad998c78856afe47 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 89411 + timestamp: 1769482314283 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.67.0-had1ee68_0.conda + sha256: a4a7dab8db4dc81c736e9a9b42bdfd97b087816e029e221380511960ac46c690 + md5: b499ce4b026493a13774bcf0f4c33849 + depends: + - __glibc >=2.17,<3.0.a0 + - c-ares >=1.34.5,<2.0a0 + - libev >=4.33,<4.34.0a0 + - libev >=4.33,<5.0a0 + - libgcc >=14 + - libstdcxx >=14 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.2,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 666600 + timestamp: 1756834976695 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda + sha256: 663444d77a42f2265f54fb8b48c5450bfff4388d9c0f8253dd7855f0d993153f + md5: 2a45e7f8af083626f009645a6481f12d + depends: + - __glibc >=2.17,<3.0.a0 + - c-ares >=1.34.6,<2.0a0 + - libev >=4.33,<4.34.0a0 + - libev >=4.33,<5.0a0 + - libgcc >=14 + - libstdcxx >=14 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.5,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 663344 + timestamp: 1773854035739 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libnghttp2-1.67.0-ha888d0e_0.conda + sha256: b03f406fd5c3f865a5e08c89b625245a9c4e026438fd1a445e45e6a0d69c2749 + md5: 981082c1cc262f514a5a2cf37cab9b81 + depends: + - c-ares >=1.34.5,<2.0a0 + - libev >=4.33,<4.34.0a0 + - libev >=4.33,<5.0a0 + - libgcc >=14 + - libstdcxx >=14 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.2,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 728661 + timestamp: 1756835019535 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libnghttp2-1.68.1-hd3077d7_0.conda + sha256: 13782715b9eeebc4ad16d36e84ca569d1495e3516aea3fe546a32caa0a597d82 + md5: be5f0f007a4500a226ef001115535a3d + depends: + - c-ares >=1.34.6,<2.0a0 + - libev >=4.33,<4.34.0a0 + - libev >=4.33,<5.0a0 + - libgcc >=14 + - libstdcxx >=14 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.5,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 726928 + timestamp: 1773854039807 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.52.0-he2ab024_0.conda + sha256: 093e4f3f62b3b07befa403e84a1f550cffe3b3961e435d42a75284f44be5f68a + md5: 12ac7d100bf260263e30a019517f42a2 + depends: + - c-ares >=1.18.1,<2.0a0 + - libcxx >=14.0.6 + - libev >=4.33,<4.34.0a0 + - libzlib >=1.2.13,<2.0.0a0 + - openssl >=3.0.8,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 613074 + timestamp: 1677678399575 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.67.0-h3338091_0.conda + sha256: c48d7e1cc927aef83ff9c48ae34dd1d7495c6ccc1edc4a3a6ba6aff1624be9ac + md5: e7630cef881b1174d40f3e69a883e55f + depends: + - __osx >=10.13 + - c-ares >=1.34.5,<2.0a0 + - libcxx >=19 + - libev >=4.33,<4.34.0a0 + - libev >=4.33,<5.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.2,<4.0a0 + license: MIT + license_family: MIT + size: 605680 + timestamp: 1756835898134 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.68.1-h70048d4_0.conda + sha256: 899551e16aac9dfb85bfc2fd98b655f4d1b7fea45720ec04ccb93d95b4d24798 + md5: dba4c95e2fe24adcae4b77ebf33559ae + depends: + - __osx >=11.0 + - c-ares >=1.34.6,<2.0a0 + - libcxx >=19 + - libev >=4.33,<4.34.0a0 + - libev >=4.33,<5.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.5,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 606749 + timestamp: 1773854765508 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.52.0-hae82a92_0.conda + sha256: 1a3944d6295dcbecdf6489ce8a05fe416ad401727c901ec390e9200a351bdb10 + md5: 1d319e95a0216f801293626a00337712 + depends: + - c-ares >=1.18.1,<2.0a0 + - libcxx >=14.0.6 + - libev >=4.33,<4.34.0a0 + - libzlib >=1.2.13,<2.0.0a0 + - openssl >=3.0.8,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 564295 + timestamp: 1677678452375 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.67.0-hc438710_0.conda + sha256: a07cb53b5ffa2d5a18afc6fd5a526a5a53dd9523fbc022148bd2f9395697c46d + md5: a4b4dd73c67df470d091312ab87bf6ae + depends: + - __osx >=11.0 + - c-ares >=1.34.5,<2.0a0 + - libcxx >=19 + - libev >=4.33,<4.34.0a0 + - libev >=4.33,<5.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.2,<4.0a0 + license: MIT + license_family: MIT + size: 575454 + timestamp: 1756835746393 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.68.1-h8f3e76b_0.conda + sha256: 2bc7bc3978066f2c274ebcbf711850cc9ab92e023e433b9631958a098d11e10a + md5: 6ea18834adbc3b33df9bd9fb45eaf95b + depends: + - __osx >=11.0 + - c-ares >=1.34.6,<2.0a0 + - libcxx >=19 + - libev >=4.33,<4.34.0a0 + - libev >=4.33,<5.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.5,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 576526 + timestamp: 1773854624224 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda + sha256: 927fe72b054277cde6cb82597d0fcf6baf127dcbce2e0a9d8925a68f1265eef5 + md5: d864d34357c3b65a4b731f78c0801dc4 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: LGPL-2.1-only + license_family: GPL + purls: [] + size: 33731 + timestamp: 1750274110928 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libnsl-2.0.1-h86ecc28_1.conda + sha256: c0dc4d84198e3eef1f37321299e48e2754ca83fd12e6284754e3cb231357c3a5 + md5: d5d58b2dc3e57073fe22303f5fed4db7 + depends: + - libgcc >=13 + license: LGPL-2.1-only + license_family: GPL + purls: [] + size: 34831 + timestamp: 1750274211 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_4.conda + sha256: 199d79c237afb0d4780ccd2fbf829cea80743df60df4705202558675e07dd2c5 + md5: be43915efc66345cccb3c310b6ed0374 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libgfortran + - libgfortran5 >=14.3.0 + constrains: + - openblas >=0.3.30,<0.3.31.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 5927939 + timestamp: 1763114673331 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libopenblas-0.3.30-pthreads_h9d3fd7e_4.conda + sha256: 794a7270ea049ec931537874cd8d2de0ef4b3cef71c055cfd8b4be6d2f4228b0 + md5: 11d7d57b7bdd01da745bbf2b67020b2e + depends: + - libgcc >=14 + - libgfortran + - libgfortran5 >=14.3.0 + constrains: + - openblas >=0.3.30,<0.3.31.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 4959359 + timestamp: 1763114173544 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.27-openmp_hfef2a42_0.conda + sha256: 45519189c0295296268cb7eabeeaa03ef54d780416c9a24be1d2a21db63a7848 + md5: 00237c9c7f2cb6725fe2960680a6e225 + depends: + - libgfortran >=5 + - libgfortran5 >=12.3.0 + - llvm-openmp >=16.0.6 + constrains: + - openblas >=0.3.27,<0.3.28.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 6047531 + timestamp: 1712366254156 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.27-openmp_h6c19121_0.conda + sha256: feb2662444fc98a4842fe54cc70b1f109b2146108e7bac2b3bbad1f219cede90 + md5: 82eba59f4eca26a9fc904d584f8761c0 + depends: + - libgfortran >=5 + - libgfortran5 >=12.3.0 + - llvm-openmp >=16.0.6 + constrains: + - openblas >=0.3.27,<0.3.28.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 2925015 + timestamp: 1712364212874 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsanitizer-14.3.0-h8f1669f_18.conda + sha256: e03ed186eefb46d7800224ad34bad1268c9d19ecb8f621380a50601c6221a4a7 + md5: ad3a0e2dc4cce549b2860e2ef0e6d75b + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14.3.0 + - libstdcxx >=14.3.0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 7949259 + timestamp: 1771377982207 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsanitizer-14.3.0-hedb4206_18.conda + sha256: 48641a458e3da681038af7ebdab143f9b6861ad9d1dcc2b4997ff2b744709423 + md5: 03feac8b6e64b72ae536fdb264e2618d + depends: + - libgcc >=14.3.0 + - libstdcxx >=14.3.0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 7526147 + timestamp: 1771377792671 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsolv-0.7.35-h9463b59_0.conda + sha256: 2fc2cdc8ea4dfd9277ae910fa3cfbf342d7890837a2002cf427fd306a869150b + md5: 21769ce326958ec230cdcbd0f2ad97eb + depends: + - libstdcxx >=14 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 518374 + timestamp: 1754325691186 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsolv-0.7.36-h9463b59_0.conda + sha256: 2a336d83e25e67b69548ee233188fa612cbce6809b3e2d45dd0b6520d75b3870 + md5: e6e2535fc6b69b08cdbaeab01aa1c277 + depends: + - libstdcxx >=14 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 519098 + timestamp: 1773328331358 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsolv-0.7.35-hdda61c4_0.conda + sha256: f68dde30e903721825214310a98ff2444857d168b12ef657c064aad22a620f06 + md5: 3e817cbcc10f018c547a1b4885094b15 + depends: + - libstdcxx >=14 + - libgcc >=14 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + size: 535157 + timestamp: 1754325829284 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsolv-0.7.36-hdda61c4_0.conda + sha256: 25019059bcbe38bdf66899d3d7b5dd48d17e01b2ff9f9e8e4d494ce51e156d75 + md5: 9b21c050436d116716f113cecd3bbcb8 + depends: + - libstdcxx >=14 + - libgcc >=14 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 535353 + timestamp: 1773328550407 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libsolv-0.7.35-h6fd32b5_0.conda + sha256: 9a510035a9b72e3e059f2cd5f031f300ed8f2971014fcdea06a84c104ce3b44b + md5: 9aca75cdbe9f71e9b2e717fb3e02cba0 + depends: + - __osx >=10.13 + - libcxx >=19 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + size: 457297 + timestamp: 1754325699071 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libsolv-0.7.36-hf97c9bc_0.conda + sha256: 622bc7d0799ba7f9825ca82fcee3d4d60bef3acdb1ad1136bfa618e479c6d338 + md5: 06871f2bcba5d0026d6698f363c36a87 + depends: + - __osx >=11.0 + - libcxx >=19 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 459988 + timestamp: 1773328382913 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsolv-0.7.35-h5f525b2_0.conda + sha256: 6da97a1c572659c2be3c3f2f39d9238dac5af2b1fd546adf2b735b0fda2ed8ec + md5: b7ffc6dc926929b9b35af5084a761f26 + depends: + - libcxx >=19 + - __osx >=11.0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + size: 428408 + timestamp: 1754325703193 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsolv-0.7.36-h7d962ec_0.conda + sha256: d7eeef792c8b12804c99b6a2c66e635e4f7d7a3d34713af070c2aa6c41c9b750 + md5: 038c047500a1db74206cf56811e80e08 + depends: + - __osx >=11.0 + - libcxx >=19 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 428233 + timestamp: 1773328439105 +- conda: https://conda.anaconda.org/conda-forge/win-64/libsolv-0.7.35-h8883371_0.conda + sha256: 80ccb7857fa2b60679a5209ca04334c86c46a441e8f4f2859308b69f8e1e928a + md5: 987be7025314bcfe936de3f0e91082b5 + depends: + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 466924 + timestamp: 1754325716718 +- conda: https://conda.anaconda.org/conda-forge/win-64/libsolv-0.7.36-h8883371_0.conda + sha256: a5abc59cd2644b964a303cc62ef8c2e08adad05d14941196130cd718d00e6eea + md5: 3ab153559588783712f13ab285a0a506 + depends: + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 468194 + timestamp: 1773328370793 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda + sha256: d716847b7deca293d2e49ed1c8ab9e4b9e04b9d780aea49a97c26925b28a7993 + md5: fd893f6a3002a635b5e50ceb9dd2c0f4 + depends: + - __glibc >=2.17,<3.0.a0 + - icu >=78.2,<79.0a0 + - libgcc >=14 + - libzlib >=1.3.1,<2.0a0 + license: blessing + purls: [] + size: 951405 + timestamp: 1772818874251 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.52.0-h10b116e_0.conda + sha256: 1ddaf91b44fae83856276f4cb7ce544ffe41d4b55c1e346b504c6b45f19098d6 + md5: 77891484f18eca74b8ad83694da9815e + depends: + - icu >=78.2,<79.0a0 + - libgcc >=14 + - libzlib >=1.3.1,<2.0a0 + license: blessing + purls: [] + size: 952296 + timestamp: 1772818881550 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.45.3-h92b6c6a_0.conda + sha256: 4d44b68fb29dcbc2216a8cae0b274b02ef9b4ae05d1d0f785362ed30b91c9b52 + md5: 68e462226209f35182ef66eda0f794ff + depends: + - libzlib >=1.2.13,<2.0.0a0 + license: Unlicense + purls: [] + size: 902546 + timestamp: 1713367776445 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.52.0-h77d7759_0.conda + sha256: f500d1cd50cfcd288d02b8fc3c3b7ecf8de6fec7b86e57ea058def02908e4231 + md5: d553eb96758e038b04027b30fe314b2d + depends: + - __osx >=11.0 + - libzlib >=1.3.1,<2.0a0 + license: blessing + purls: [] + size: 996526 + timestamp: 1772819669038 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.45.3-h091b4b1_0.conda + sha256: 4337f466eb55bbdc74e168b52ec8c38f598e3664244ec7a2536009036e2066cc + md5: c8c1186c7f3351f6ffddb97b1f54fc58 + depends: + - libzlib >=1.2.13,<2.0.0a0 + license: Unlicense + purls: [] + size: 824794 + timestamp: 1713367748819 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.52.0-h1ae2325_0.conda + sha256: beb0fd5594d6d7c7cd42c992b6bb4d66cbb39d6c94a8234f15956da99a04306c + md5: f6233a3fddc35a2ec9f617f79d6f3d71 + depends: + - __osx >=11.0 + - icu >=78.2,<79.0a0 + - libzlib >=1.3.1,<2.0a0 + license: blessing + purls: [] + size: 918420 + timestamp: 1772819478684 +- conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.52.0-hf5d6505_0.conda + sha256: 5fccf1e4e4062f8b9a554abf4f9735a98e70f82e2865d0bfdb47b9de94887583 + md5: 8830689d537fda55f990620680934bb1 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: blessing + purls: [] + size: 1297302 + timestamp: 1772818899033 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda + sha256: fa39bfd69228a13e553bd24601332b7cfeb30ca11a3ca50bb028108fe90a7661 + md5: eecce068c7e4eddeb169591baac20ac4 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.0,<4.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 304790 + timestamp: 1745608545575 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libssh2-1.11.1-h18c354c_0.conda + sha256: 1e289bcce4ee6a5817a19c66e296f3c644dcfa6e562e5c1cba807270798814e7 + md5: eecc495bcfdd9da8058969656f916cc2 + depends: + - libgcc >=13 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.0,<4.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 311396 + timestamp: 1745609845915 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.11.0-hd019ec5_0.conda + sha256: f3886763b88f4b24265db6036535ef77b7b77ce91b1cbe588c0fbdd861eec515 + md5: ca3a72efba692c59a90d4b9fc0dfe774 + depends: + - libzlib >=1.2.13,<2.0.0a0 + - openssl >=3.1.1,<4.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 259556 + timestamp: 1685837820566 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.11.1-hed3591d_0.conda + sha256: 00654ba9e5f73aa1f75c1f69db34a19029e970a4aeb0fa8615934d8e9c369c3c + md5: a6cb15db1c2dc4d3a5f6cf3772e09e81 + depends: + - __osx >=10.13 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.0,<4.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 284216 + timestamp: 1745608575796 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.0-h7a5bd25_0.conda + sha256: bb57d0c53289721fff1eeb3103a1c6a988178e88d8a8f4345b0b91a35f0e0015 + md5: 029f7dc931a3b626b94823bc77830b01 + depends: + - libzlib >=1.2.13,<2.0.0a0 + - openssl >=3.1.1,<4.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 255610 + timestamp: 1685837894256 +- 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/win-64/libssh2-1.11.1-h9aa295b_0.conda + sha256: cbdf93898f2e27cefca5f3fe46519335d1fab25c4ea2a11b11502ff63e602c09 + md5: 9dce2f112bfd3400f4f432b3d0ac07b2 + depends: + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.0,<4.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 292785 + timestamp: 1745608759342 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda + sha256: 78668020064fdaa27e9ab65cd2997e2c837b564ab26ce3bf0e58a2ce1a525c6e + md5: 1b08cd684f34175e4514474793d44bcb + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc 15.2.0 he0feb66_18 + constrains: + - libstdcxx-ng ==15.2.0=*_18 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 5852330 + timestamp: 1771378262446 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_18.conda + sha256: 31fdb9ffafad106a213192d8319b9f810e05abca9c5436b60e507afb35a6bc40 + md5: f56573d05e3b735cb03efeb64a15f388 + depends: + - libgcc 15.2.0 h8acb6b2_18 + constrains: + - libstdcxx-ng ==15.2.0=*_18 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 5541411 + timestamp: 1771378162499 +- conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-64-14.3.0-h9f08a49_118.conda + sha256: b1c3824769b92a1486bf3e2cc5f13304d83ae613ea061b7bc47bb6080d6dfdba + md5: 865a399bce236119301ebd1532fced8d + depends: + - __unix + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 20171098 + timestamp: 1771377827750 +- conda: https://conda.anaconda.org/conda-forge/noarch/libstdcxx-devel_linux-aarch64-14.3.0-h57c8d61_118.conda + sha256: 609585a02b05a2b0f2cabb18849328455cbce576f2e3eb8108f3ef7f4cb165a6 + md5: bcf29f2ed914259a258204b05346abb1 + depends: + - __unix + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 17565700 + timestamp: 1771377672552 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda + sha256: 3c902ffd673cb3c6ddde624cdb80f870b6c835f8bf28384b0016e7d444dd0145 + md5: 6235adb93d064ecdf3d44faee6f468de + depends: + - libstdcxx 15.2.0 h934c35e_18 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 27575 + timestamp: 1771378314494 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-ng-15.2.0-hdbbeba8_18.conda + sha256: 035a31cde134e706e30029a837a31f729ad32b7c5bca023271dfe91a8ba6c896 + md5: 699d294376fe18d80b7ce7876c3a875d + depends: + - libstdcxx 15.2.0 hef695bb_18 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 27645 + timestamp: 1771378204663 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda + sha256: 1a7539cfa7df00714e8943e18de0b06cceef6778e420a5ee3a2a145773758aee + md5: db409b7c1720428638e7c0d509d3e1b5 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 40311 + timestamp: 1766271528534 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42-h5347b49_0.conda + sha256: bc1b08c92626c91500fd9f26f2c797f3eb153b627d53e9c13cd167f1e12b2829 + md5: 38ffe67b78c9d4de527be8315e5ada2c + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 40297 + timestamp: 1775052476770 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.41.3-h1022ec0_0.conda + sha256: c37a8e89b700646f3252608f8368e7eb8e2a44886b92776e57ad7601fc402a11 + md5: cf2861212053d05f27ec49c3784ff8bb + depends: + - libgcc >=14 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 43453 + timestamp: 1766271546875 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.42-h1022ec0_0.conda + sha256: 7d427edf58c702c337bf62bc90f355b7fc374a65fd9f70ea7a490f13bb76b1b9 + md5: a0b5de740d01c390bdbb46d7503c9fab + depends: + - libgcc >=14 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 43567 + timestamp: 1775052485727 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libuv-1.51.0-hb03c661_1.conda + sha256: c180f4124a889ac343fc59d15558e93667d894a966ec6fdb61da1604481be26b + md5: 0f03292cc56bf91a077a134ea8747118 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: MIT + license_family: MIT + purls: [] + size: 895108 + timestamp: 1753948278280 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuv-1.51.0-he30d5cf_1.conda + sha256: 7a0fb5638582efc887a18b7d270b0c4a6f6e681bf401cab25ebafa2482569e90 + md5: 8e62bf5af966325ee416f19c6f14ffa3 + depends: + - libgcc >=14 + license: MIT + license_family: MIT + purls: [] + size: 629238 + timestamp: 1753948296190 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libuv-1.48.0-h67532ce_0.conda + sha256: fb87f7bfd464a3a841d23f418c86a206818da0c4346984392071d9342c9ea367 + md5: c8e7344c74f0d86584f7ecdc9f25c198 + license: MIT + license_family: MIT + purls: [] + size: 407040 + timestamp: 1709913680478 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libuv-1.48.0-h93a5062_0.conda + sha256: 60bed2a7a85096387ab0381cbc32ea2da7f8dd99bd90e440983019c0cdd96ad1 + md5: abfd49e80f13453b62a56be226120ea8 + license: MIT + license_family: MIT + purls: [] + size: 405988 + timestamp: 1709913494015 +- conda: https://conda.anaconda.org/conda-forge/win-64/libuv-1.51.0-hfd05255_1.conda + sha256: f03dc82e6fb1725788e73ae97f0cd3d820d5af0d351a274104a0767035444c59 + md5: 31e1545994c48efc3e6ea32ca02a8724 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: MIT + license_family: MIT + purls: [] + size: 297087 + timestamp: 1753948490874 +- conda: https://conda.anaconda.org/conda-forge/win-64/libwinpthread-12.0.0.r4.gg4f2fc60ca-h57928b3_10.conda + sha256: 0fccf2d17026255b6e10ace1f191d0a2a18f2d65088fd02430be17c701f8ffe0 + md5: 8a86073cf3b343b87d03f41790d8b4e5 + depends: + - ucrt + constrains: + - pthreads-win32 <0.0a0 + - msys2-conda-epoch <0.0a0 + license: MIT AND BSD-3-Clause-Clear + purls: [] + size: 36621 + timestamp: 1759768399557 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda + sha256: 6ae68e0b86423ef188196fff6207ed0c8195dd84273cb5623b85aa08033a410c + md5: 5aa797f8787fe7a17d1b0821485b5adc + depends: + - libgcc-ng >=12 + license: LGPL-2.1-or-later + purls: [] + size: 100393 + timestamp: 1702724383534 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxcrypt-4.4.36-h31becfc_1.conda + sha256: 6b46c397644091b8a26a3048636d10b989b1bf266d4be5e9474bf763f828f41f + md5: b4df5d7d4b63579d081fd3a4cf99740e + depends: + - libgcc-ng >=12 + license: LGPL-2.1-or-later + purls: [] + size: 114269 + timestamp: 1702724369203 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.2-he237659_0.conda + sha256: 275c324f87bda1a3b67d2f4fcc3555eeff9e228a37655aa001284a7ceb6b0392 + md5: e49238a1609f9a4a844b09d9926f2c3d + depends: + - __glibc >=2.17,<3.0.a0 + - icu >=78.2,<79.0a0 + - libgcc >=14 + - libiconv >=1.18,<2.0a0 + - liblzma >=5.8.2,<6.0a0 + - libxml2-16 2.15.2 hca6bf5a_0 + - libzlib >=1.3.1,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 45968 + timestamp: 1772704614539 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-2.15.2-h825857f_0.conda + sha256: 3e51e1952cb60c8107094b6b78473d91ff49d428ad4bef6806124b383e8fe29c + md5: 19de96909ee1198e2853acd8aba89f6c + depends: + - icu >=78.2,<79.0a0 + - libgcc >=14 + - libiconv >=1.18,<2.0a0 + - liblzma >=5.8.2,<6.0a0 + - libxml2-16 2.15.2 h79dcc73_0 + - libzlib >=1.3.1,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 47837 + timestamp: 1772704681112 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.12.6-hc0ae0f7_2.conda + sha256: 2598a525b1769338f96c3d4badad7d8b95c9ddcea86db3f9479a274803190e5c + md5: 50b997370584f2c83ca0c38e9028eab9 + depends: + - icu >=73.2,<74.0a0 + - libiconv >=1.17,<2.0a0 + - libzlib >=1.2.13,<2.0.0a0 + - xz >=5.2.6,<6.0a0 + license: MIT + license_family: MIT + purls: [] + size: 619622 + timestamp: 1713314870641 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.15.2-hd552753_0.conda + sha256: 5b9e8a5146275ac0539231f646ee51a9e4629e730026ff69dadff35bfb745911 + md5: eea3155f3b4a3b75af504c871ec23858 + depends: + - __osx >=11.0 + - icu >=78.2,<79.0a0 + - libiconv >=1.18,<2.0a0 + - liblzma >=5.8.2,<6.0a0 + - libxml2-16 2.15.2 h7a90416_0 + - libzlib >=1.3.1,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 41106 + timestamp: 1772705465931 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-2.12.6-h35eab27_2.conda + sha256: 14870a455d478682a60655e3026c51d01ebc1747ccce726ae495a693b304c9b1 + md5: d3a4a3d691494491a08e05f66a0aa35a + depends: + - icu >=73.2,<74.0a0 + - libiconv >=1.17,<2.0a0 + - libzlib >=1.3.1,<1.4.0a0 + - xz >=5.2.6,<6.0a0 + license: MIT + license_family: MIT + purls: [] + size: 587544 + timestamp: 1713314830067 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-2.15.2-h8d039ee_0.conda + sha256: 99cb32dd06a2e58c12981b71a84b052293f27b5ab042e3f21d895f5d7ee13eff + md5: e476ba84e57f2bd2004a27381812ad4e + depends: + - __osx >=11.0 + - icu >=78.2,<79.0a0 + - libiconv >=1.18,<2.0a0 + - liblzma >=5.8.2,<6.0a0 + - libxml2-16 2.15.2 h5ef1a60_0 + - libzlib >=1.3.1,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 41206 + timestamp: 1772704982288 +- conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-2.15.2-h5d26750_0.conda + sha256: f905eb7046987c336122121759e7f09144729f6898f48cd06df2a945b86998d8 + md5: 1007e1bfe181a2aee214779ee7f13d30 + depends: + - libiconv >=1.18,<2.0a0 + - liblzma >=5.8.2,<6.0a0 + - libxml2-16 2.15.2 h692994f_0 + - libzlib >=1.3.1,<2.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + constrains: + - icu <0.0a0 + license: MIT + license_family: MIT + purls: [] + size: 43681 + timestamp: 1772704748950 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-16-2.15.2-hca6bf5a_0.conda + sha256: 08d2b34b49bec9613784f868209bb7c3bb8840d6cf835ff692e036b09745188c + md5: f3bc152cb4f86babe30f3a4bf0dbef69 + depends: + - __glibc >=2.17,<3.0.a0 + - icu >=78.2,<79.0a0 + - libgcc >=14 + - libiconv >=1.18,<2.0a0 + - liblzma >=5.8.2,<6.0a0 + - libzlib >=1.3.1,<2.0a0 + constrains: + - libxml2 2.15.2 + license: MIT + license_family: MIT + purls: [] + size: 557492 + timestamp: 1772704601644 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libxml2-16-2.15.2-h79dcc73_0.conda + sha256: da6b2ebbcecc158200d90be39514e4e902971628029b35b7f6ad57270659c5d9 + md5: e3ec9079759d35b875097d6a9a69e744 + depends: + - icu >=78.2,<79.0a0 + - libgcc >=14 + - libiconv >=1.18,<2.0a0 + - liblzma >=5.8.2,<6.0a0 + - libzlib >=1.3.1,<2.0a0 + constrains: + - libxml2 2.15.2 + license: MIT + license_family: MIT + purls: [] + size: 598438 + timestamp: 1772704671710 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libxml2-16-2.15.2-h7a90416_0.conda + sha256: f67e4b7d7f97e57ecd611a42e42d5f6c047fd3d1eb8270813b888924440c8a59 + md5: 0c8bdbfd118f5963ab343846094932a3 + depends: + - __osx >=11.0 + - icu >=78.2,<79.0a0 + - libiconv >=1.18,<2.0a0 + - liblzma >=5.8.2,<6.0a0 + - libzlib >=1.3.1,<2.0a0 + constrains: + - libxml2 2.15.2 + license: MIT + license_family: MIT + purls: [] + size: 495922 + timestamp: 1772705426323 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-16-2.15.2-h5ef1a60_0.conda + sha256: 6432259204e78c8a8a815afae987fbf60bd722605fe2c4b022e65196b17d4537 + md5: b284e2b02d53ef7981613839fb86beee + depends: + - __osx >=11.0 + - icu >=78.2,<79.0a0 + - libiconv >=1.18,<2.0a0 + - liblzma >=5.8.2,<6.0a0 + - libzlib >=1.3.1,<2.0a0 + constrains: + - libxml2 2.15.2 + license: MIT + license_family: MIT + purls: [] + size: 466220 + timestamp: 1772704950232 +- conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-16-2.15.2-h692994f_0.conda + sha256: b8c71b3b609c7cfe17f3f2a47c75394d7b30acfb8b34ad7a049ea8757b4d33df + md5: e365238134188e42ed36ee996159d482 + depends: + - libiconv >=1.18,<2.0a0 + - liblzma >=5.8.2,<6.0a0 + - libzlib >=1.3.1,<2.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + constrains: + - libxml2 2.15.2 + - icu <0.0a0 + license: MIT + license_family: MIT + purls: [] + size: 520078 + timestamp: 1772704728534 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda + sha256: d4bfe88d7cb447768e31650f06257995601f89076080e76df55e3112d4e47dc4 + md5: edb0dca6bc32e4f4789199455a1dbeb8 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + constrains: + - zlib 1.3.1 *_2 + license: Zlib + license_family: Other + purls: [] + size: 60963 + timestamp: 1727963148474 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda + sha256: 55044c403570f0dc26e6364de4dc5368e5f3fc7ff103e867c487e2b5ab2bcda9 + md5: d87ff7921124eccd67248aa483c23fec + depends: + - __glibc >=2.17,<3.0.a0 + constrains: + - zlib 1.3.2 *_2 + license: Zlib + license_family: Other + purls: [] + size: 63629 + timestamp: 1774072609062 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.1-h86ecc28_2.conda + sha256: 5a2c1eeef69342e88a98d1d95bff1603727ab1ff4ee0e421522acd8813439b84 + md5: 08aad7cbe9f5a6b460d0976076b6ae64 + depends: + - libgcc >=13 + constrains: + - zlib 1.3.1 *_2 + license: Zlib + license_family: Other + purls: [] + size: 66657 + timestamp: 1727963199518 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_2.conda + sha256: eb111e32e5a7313a5bf799c7fb2419051fa2fe7eff74769fac8d5a448b309f7f + md5: 502006882cf5461adced436e410046d1 + constrains: + - zlib 1.3.2 *_2 + license: Zlib + license_family: Other + purls: [] + size: 69833 + timestamp: 1774072605429 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.1-hd23fc13_2.conda + sha256: 8412f96504fc5993a63edf1e211d042a1fd5b1d51dedec755d2058948fcced09 + md5: 003a54a4e32b02f7355b50a837e699da + depends: + - __osx >=10.13 + constrains: + - zlib 1.3.1 *_2 + license: Zlib + license_family: Other + size: 57133 + timestamp: 1727963183990 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.1-hd75f5a5_0.conda + sha256: 49fd2bde256952ab6a8265f3b2978ae624db1f096e3340253699e2534426244a + md5: fad941436715cc1b6f6e55a14372f70c + constrains: + - zlib 1.3.1 *_0 + license: Zlib + license_family: Other + purls: [] + size: 57480 + timestamp: 1709241092733 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.2-hbb4bfdb_2.conda + sha256: 4c6da089952b2d70150c74234679d6f7ac04f4a98f9432dec724968f912691e7 + md5: 30439ff30578e504ee5e0b390afc8c65 + depends: + - __osx >=11.0 + constrains: + - zlib 1.3.2 *_2 + license: Zlib + license_family: Other + purls: [] + size: 59000 + timestamp: 1774073052242 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.1-h0d3ecfb_0.conda + sha256: 9c59bd3f3e3e1900620e3a85c04d3a3699cb93c714333d06cb8afdd7addaae9d + md5: 2a2463424cc5e961a6d04bbbfb5838cf + constrains: + - zlib 1.3.1 *_0 + license: Zlib + license_family: Other + purls: [] + size: 47040 + timestamp: 1709241137619 +- 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 + size: 46438 + timestamp: 1727963202283 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda + sha256: 361415a698514b19a852f5d1123c5da746d4642139904156ddfca7c922d23a05 + md5: bc5a5721b6439f2f62a84f2548136082 + depends: + - __osx >=11.0 + constrains: + - zlib 1.3.2 *_2 + license: Zlib + license_family: Other + purls: [] + size: 47759 + timestamp: 1774072956767 +- conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.1-h2466b09_2.conda + sha256: ba945c6493449bed0e6e29883c4943817f7c79cbff52b83360f7b341277c6402 + md5: 41fbfac52c601159df6c01f875de31b9 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + constrains: + - zlib 1.3.1 *_2 + license: Zlib + license_family: Other + purls: [] + size: 55476 + timestamp: 1727963768015 +- conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.2-hfd05255_2.conda + sha256: 88609816e0cc7452bac637aaf65783e5edf4fee8a9f8e22bdc3a75882c536061 + md5: dbabbd6234dea34040e631f87676292f + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + constrains: + - zlib 1.3.2 *_2 + license: Zlib + license_family: Other + purls: [] + size: 58347 + timestamp: 1774072851498 +- conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-18.1.3-hb6ac08f_0.conda + sha256: 997e4169ea474a7bc137fed3b5f4d94b1175162b3318e8cb3943003e460fe458 + md5: 506f270f4f00980d27cc1fc127e0ed37 + constrains: + - openmp 18.1.3|18.1.3.* + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + purls: [] + size: 300597 + timestamp: 1712603382363 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-18.1.3-hcd81f8e_0.conda + sha256: 4cb4eadd633669496ed70c580c965f5f2ed29336890636c61a53e9c1c1541073 + md5: 24cbf1fb1b83056f8ba1beaac0619bf8 + constrains: + - openmp 18.1.3|18.1.3.* + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + purls: [] + size: 276320 + timestamp: 1712603367897 +- conda: https://conda.anaconda.org/conda-forge/win-64/llvm-openmp-22.1.0-h4fa8253_0.conda + sha256: bb55a3736380759d338f87aac68df4fd7d845ae090b94400525f5d21a55eea31 + md5: e5505e0b7d6ef5c19d5c0c1884a2f494 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + constrains: + - openmp 22.1.0|22.1.0.* + - intel-openmp <0.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + purls: [] + size: 347404 + timestamp: 1772025050288 +- conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-tools-18.1.3-hbcf5fad_0.conda + sha256: be89293b54032198a28d3a4b91e50eb4d79e252d9e3ab609501ea0324fbf478a + md5: f91db97d91a080e0024307fa3808cc7b + depends: + - libllvm18 18.1.3 hbcf5fad_0 + - libxml2 >=2.12.6,<2.14.0a0 + - libzlib >=1.2.13,<2.0.0a0 + - zstd >=1.5.5,<1.6.0a0 + constrains: + - clang-tools 18.1.3 + - llvmdev 18.1.3 + - llvm 18.1.3 + - clang 18.1.3 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 24449337 + timestamp: 1712518244229 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-tools-18.1.3-h30cc82d_0.conda + sha256: 48eb7b17ca6de1b43dfddc3b4a629a8a9764c9da3f3012980e1b917c71f06a4f + md5: 505aef673d805f9efe0c61954a6a99d0 + depends: + - libllvm18 18.1.3 h30cc82d_0 + - libxml2 >=2.12.6,<2.14.0a0 + - libzlib >=1.2.13,<2.0.0a0 + - zstd >=1.5.5,<1.6.0a0 + constrains: + - llvm 18.1.3 + - clang-tools 18.1.3 + - clang 18.1.3 + - llvmdev 18.1.3 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + purls: [] + size: 23023681 + timestamp: 1712517958538 +- conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda + sha256: 47326f811392a5fd3055f0f773036c392d26fdb32e4d8e7a8197eed951489346 + md5: 9de5350a85c4a20c685259b889aa6393 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libstdcxx >=13 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 167055 + timestamp: 1733741040117 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lz4-c-1.10.0-h5ad3122_1.conda + sha256: 67e55058d275beea76c1882399640c37b5be8be4eb39354c94b610928e9a0573 + md5: 6654e411da94011e8fbe004eacb8fe11 + depends: + - libgcc >=13 + - libstdcxx >=13 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 184953 + timestamp: 1733740984533 +- conda: https://conda.anaconda.org/conda-forge/osx-64/lz4-c-1.10.0-h240833e_1.conda + sha256: 8da3c9d4b596e481750440c0250a7e18521e7f69a47e1c8415d568c847c08a1c + md5: d6b9bd7e356abd7e3a633d59b753495a + depends: + - __osx >=10.13 + - libcxx >=18 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 159500 + timestamp: 1733741074747 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/lz4-c-1.10.0-h286801f_1.conda + sha256: 94d3e2a485dab8bdfdd4837880bde3dd0d701e2b97d6134b8806b7c8e69c8652 + md5: 01511afc6cc1909c5303cf31be17b44f + depends: + - __osx >=11.0 + - libcxx >=18 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 148824 + timestamp: 1733741047892 +- conda: https://conda.anaconda.org/conda-forge/win-64/lz4-c-1.10.0-h2466b09_1.conda + sha256: 632cf3bdaf7a7aeb846de310b6044d90917728c73c77f138f08aa9438fc4d6b5 + md5: 0b69331897a92fac3d8923549d48d092 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 139891 + timestamp: 1733741168264 +- conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-h280c20c_1002.conda + sha256: 5c6bbeec116e29f08e3dad3d0524e9bc5527098e12fc432c0e5ca53ea16337d4 + md5: 45161d96307e3a447cc3eb5896cf6f8c + depends: + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + license: GPL-2.0-or-later + license_family: GPL + purls: [] + size: 191060 + timestamp: 1753889274283 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/lzo-2.10-h80f16a2_1002.conda + sha256: 036428c7b9fd22889108d04c91cecc431f95dc3dba2ede3057330c8125080fd5 + md5: 97af2e332449dd9e92ad7db93b02e918 + depends: + - libgcc >=14 + license: GPL-2.0-or-later + license_family: GPL + purls: [] + size: 190187 + timestamp: 1753889356434 +- conda: https://conda.anaconda.org/conda-forge/osx-64/lzo-2.10-h4132b18_1002.conda + sha256: bb5fe07123a7d573af281d04b75e1e77e87e62c5c4eb66d9781aa919450510d1 + md5: 5a047b9aa4be1dcdb62bd561d9eb6ceb + depends: + - __osx >=10.13 + license: GPL-2.0-or-later + license_family: GPL + purls: [] + size: 174634 + timestamp: 1753889269889 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/lzo-2.10-h925e9cb_1002.conda + sha256: db40fd25c6306bfda469f84cddd8b5ebb9aa08d509cecb49dfd0bb8228466d0c + md5: e56eaa1beab0e7fed559ae9c0264dd88 + depends: + - __osx >=11.0 + license: GPL-2.0-or-later + license_family: GPL + purls: [] + size: 152755 + timestamp: 1753889267953 +- conda: https://conda.anaconda.org/conda-forge/win-64/lzo-2.10-h6a83c73_1002.conda + sha256: 344f4f225c6dfb523fb477995545542224c37a5c86161f053a1a18fe547aa979 + md5: c5cb4159f0eea65663b31dd1e49bbb71 + depends: + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + license: GPL-2.0-or-later + license_family: GPL + purls: [] + size: 165589 + timestamp: 1753889311940 +- pypi: https://files.pythonhosted.org/packages/c7/d1/a9f36f8ecdf0fb7c9b1e78c8d7af12b8c8754e74851ac7b94a8305540fc7/macholib-1.16.4-py2.py3-none-any.whl + name: macholib + version: 1.16.4 + sha256: da1a3fa8266e30f0ce7e97c6a54eefaae8edd1e5f86f3eb8b95457cae90265ea + requires_dist: + - altgraph>=0.17 +- pypi: https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl + name: markdown-it-py + version: 4.0.0 + sha256: 87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147 + requires_dist: + - mdurl~=0.1 + - psutil ; extra == 'benchmarking' + - pytest ; extra == 'benchmarking' + - pytest-benchmark ; extra == 'benchmarking' + - commonmark~=0.9 ; extra == 'compare' + - markdown~=3.4 ; extra == 'compare' + - mistletoe~=1.0 ; extra == 'compare' + - mistune~=3.0 ; extra == 'compare' + - panflute~=2.3 ; extra == 'compare' + - markdown-it-pyrs ; extra == 'compare' + - linkify-it-py>=1,<3 ; extra == 'linkify' + - mdit-py-plugins>=0.5.0 ; extra == 'plugins' + - gprof2dot ; extra == 'profiling' + - mdit-py-plugins>=0.5.0 ; extra == 'rtd' + - myst-parser ; extra == 'rtd' + - pyyaml ; extra == 'rtd' + - sphinx ; extra == 'rtd' + - sphinx-copybutton ; extra == 'rtd' + - sphinx-design ; extra == 'rtd' + - sphinx-book-theme~=1.0 ; extra == 'rtd' + - jupyter-sphinx ; extra == 'rtd' + - ipykernel ; extra == 'rtd' + - coverage ; extra == 'testing' + - pytest ; extra == 'testing' + - pytest-cov ; extra == 'testing' + - pytest-regressions ; extra == 'testing' + - requests ; extra == 'testing' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl + name: mdurl + version: 0.1.2 + sha256: 84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 + requires_python: '>=3.7' +- conda: https://conda.anaconda.org/conda-forge/linux-64/menuinst-2.4.2-py310hff52083_0.conda + sha256: ec100872ca86c8dc6a08b16d0046661dd85ebb6b6910c57dfcafecbdc622a1ba + md5: 937b4f62485b63f71ee8d50ae021cc33 + depends: + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + license: BSD-3-Clause AND MIT + purls: + - pkg:pypi/menuinst?source=hash-mapping + size: 155578 + timestamp: 1765733217218 +- conda: https://conda.anaconda.org/conda-forge/linux-64/menuinst-2.4.2-py311h38be061_0.conda + sha256: 096f1db22fd47ddcf5df82aed016ef8cef4c1b810925bf63b67cfc3f9ba67cdb + md5: ba48e568ec4fdbcb8f3fef87bca9fddb + depends: + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: BSD-3-Clause AND MIT + purls: + - pkg:pypi/menuinst?source=hash-mapping + size: 186910 + timestamp: 1765733175922 +- conda: https://conda.anaconda.org/conda-forge/linux-64/menuinst-2.4.2-py314hdafbbf9_0.conda + sha256: 223306ba7f78599abc65f8ca14116650c228cbdca273ca15804544ac343a9e69 + md5: 608ee3d8065e9b1e9e1f3115d8aab9ab + depends: + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + license: BSD-3-Clause AND MIT + purls: + - pkg:pypi/menuinst?source=hash-mapping + size: 188752 + timestamp: 1765733220513 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/menuinst-2.4.2-py310h4c7bcd0_0.conda + sha256: 331b93ad811c1033b5d22a23541b23c75c0d1b31ad0ed2d6f4117a79f3676f0e + md5: 928764c3c75aaabcc1bac5ebf4a8a7c2 + depends: + - python >=3.10,<3.11.0a0 + - python >=3.10,<3.11.0a0 *_cpython + - python_abi 3.10.* *_cp310 + license: BSD-3-Clause AND MIT + purls: + - pkg:pypi/menuinst?source=hash-mapping + size: 156117 + timestamp: 1765733228621 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/menuinst-2.4.2-py311hec3470c_0.conda + sha256: 803b3fc3b4c0c4abc8d2c720793c1cbe784506762a0dcdcb736805c0aebc797d + md5: b2b440c867b680594a750a00c3425417 + depends: + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: BSD-3-Clause AND MIT + purls: + - pkg:pypi/menuinst?source=hash-mapping + size: 187037 + timestamp: 1765733232285 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/menuinst-2.4.2-py314h28a4750_0.conda + sha256: ed5d3d0b646207b15aea1022ed10ccccfebfa271b152eeb6169b767a02b632a5 + md5: 41fc65edb06fbcc2c2e68c02d06f6bf7 + depends: + - python >=3.14,<3.15.0a0 + - python >=3.14,<3.15.0a0 *_cp314 + - python_abi 3.14.* *_cp314 + license: BSD-3-Clause AND MIT + purls: + - pkg:pypi/menuinst?source=hash-mapping + size: 188584 + timestamp: 1765733234092 +- conda: https://conda.anaconda.org/conda-forge/osx-64/menuinst-2.4.2-py314hee6578b_0.conda + sha256: f9967b4794840bbc1e1a02b0f8e2d9c2a97216e1d5eb88024ca3e34d6f0c7838 + md5: 70759a82982d21ee091d7004b945048a + depends: + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + license: BSD-3-Clause AND MIT + purls: + - pkg:pypi/menuinst?source=hash-mapping + size: 187629 + timestamp: 1765733352246 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/menuinst-2.4.2-py314h4dc9dd8_0.conda + sha256: cfe6079a2193f9ecf0279bff01eb57499a5a081607ea3c83b2c5522c00a538ca + md5: 312610ff2ccaa1e4995f4fb3d8c04f96 + depends: + - python >=3.14,<3.15.0a0 + - python >=3.14,<3.15.0a0 *_cp314 + - python_abi 3.14.* *_cp314 + license: BSD-3-Clause AND MIT + purls: + - pkg:pypi/menuinst?source=hash-mapping + size: 188284 + timestamp: 1765733422732 +- conda: https://conda.anaconda.org/conda-forge/win-64/menuinst-2.4.2-py310h73ae2b4_0.conda + sha256: 3b5ab966d63a2e217f15a437be470bee04d69b63f5205a5d1a8d012008ba6b04 + md5: fd40b3f1395d1b1e9071961d90a3f0f0 + depends: + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: BSD-3-Clause AND MIT + purls: + - pkg:pypi/menuinst?source=hash-mapping + size: 146344 + timestamp: 1765733517640 +- conda: https://conda.anaconda.org/conda-forge/win-64/menuinst-2.4.2-py311h3e6a449_0.conda + sha256: 0482c0c5962ba3da648071affec41b416a51c6afbf52264ea40434e43993b0cf + md5: 25b1fdcd2436106cab080dc1932dba63 + depends: + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: BSD-3-Clause AND MIT + purls: + - pkg:pypi/menuinst?source=hash-mapping + size: 179383 + timestamp: 1765733304312 +- conda: https://conda.anaconda.org/conda-forge/win-64/menuinst-2.4.2-py314h13fbf68_0.conda + sha256: 1f4535acbc5a2d75e2b6d83fca659c468bc2597af798fdf2e45091265a094a32 + md5: ced101aaa08315eb8a058b1190500d12 + depends: + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: BSD-3-Clause AND MIT + purls: + - pkg:pypi/menuinst?source=hash-mapping + size: 179510 + timestamp: 1765733497067 +- conda: https://conda.anaconda.org/conda-forge/win-64/mkl-2025.3.0-hac47afa_455.conda + sha256: b2b4c84b95210760e4d12319416c60ab66e03674ccdcbd14aeb59f82ebb1318d + md5: fd05d1e894497b012d05a804232254ed + depends: + - llvm-openmp >=21.1.8 + - tbb >=2022.3.0 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: LicenseRef-IntelSimplifiedSoftwareOct2022 + license_family: Proprietary + purls: [] + size: 100224829 + timestamp: 1767634557029 +- pypi: https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl + name: more-itertools + version: 10.8.0 + sha256: 52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b + requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.1.2-py310h03d9f68_1.conda + sha256: 61cf3572d6afa3fa711c5f970a832783d2c281facb7b3b946a6b71a0bac2c592 + md5: 5eea9d8f8fcf49751dab7927cb0dfc3f + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/msgpack?source=hash-mapping + size: 95105 + timestamp: 1762504073388 +- conda: https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.1.2-py311hdf67eae_1.conda + sha256: 8c81a6208def64afc3e208326d78d7af60bcbc32d44afe1269b332df84084f29 + md5: c1153b2cb3318889ce624a3b4f0db7f7 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/msgpack?source=hash-mapping + size: 102979 + timestamp: 1762504186626 +- conda: https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.1.2-py314h9891dd4_1.conda + sha256: d41c2734d314303e329680aeef282766fe399a0ce63297a68a2f8f9b43b1b68a + md5: c6752022dcdbf4b9ef94163de1ab7f03 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/msgpack?source=hash-mapping + size: 103380 + timestamp: 1762504077009 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/msgpack-python-1.1.2-py310h0992a49_1.conda + sha256: 663967ac8fbe9a5e32246784d0c6c08be8394dab5c045297121550beb967b127 + md5: 0d9ac8c2994a3681e44edcf9bb1a3e8e + depends: + - libgcc >=14 + - libstdcxx >=14 + - python >=3.10,<3.11.0a0 + - python >=3.10,<3.11.0a0 *_cpython + - python_abi 3.10.* *_cp310 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/msgpack?source=hash-mapping + size: 93092 + timestamp: 1762504199089 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/msgpack-python-1.1.2-py311hfca10b7_1.conda + sha256: 35a36e3062bf84a70c0105b1553a1aa7b16a1dad19a97945efeea2b92ca95f23 + md5: 560e361fc9aff96fdd179e7e5d41471e + depends: + - libgcc >=14 + - libstdcxx >=14 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/msgpack?source=hash-mapping + size: 100340 + timestamp: 1762504276815 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/msgpack-python-1.1.2-py314hd7d8586_1.conda + sha256: 124a778a7065d75d9d36d80563e75d3a13455b160a761cd38a5ce8f50f87705c + md5: e93c66201de71acb9e99d94f84f897b1 + depends: + - libgcc >=14 + - libstdcxx >=14 + - python >=3.14,<3.15.0a0 + - python >=3.14,<3.15.0a0 *_cp314 + - python_abi 3.14.* *_cp314 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/msgpack?source=hash-mapping + size: 100176 + timestamp: 1762504193305 +- conda: https://conda.anaconda.org/conda-forge/osx-64/msgpack-python-1.1.2-py314h00ed6fe_1.conda + sha256: 1e82a903c5b5fb1555851ff1ef9068a538f4d8652eee2c31935d2d6d326a99f7 + md5: 977962f6bb6f922ee0caabcb5a1b1d8c + depends: + - __osx >=10.13 + - libcxx >=19 + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/msgpack?source=hash-mapping + size: 92312 + timestamp: 1762504434513 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/msgpack-python-1.1.2-py314h784bc60_1.conda + sha256: 9dc4ebe88064cf96bb97a4de83be10fbc52a24d2ff48a4561fb0fed337b526f0 + md5: 305227e4de261896033ad8081e8b52ae + depends: + - __osx >=11.0 + - libcxx >=19 + - python >=3.14,<3.15.0a0 + - python >=3.14,<3.15.0a0 *_cp314 + - python_abi 3.14.* *_cp314 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/msgpack?source=hash-mapping + size: 92381 + timestamp: 1762504601981 +- conda: https://conda.anaconda.org/conda-forge/win-64/msgpack-python-1.1.2-py310he9f1925_1.conda + sha256: 6b7bfd07c5be57df2922e2f5238751ee6bb09d81540a44c6554d059eac2a3bd5 + md5: 65fb9838e245ef4bea6cab32a7056dfc + depends: + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/msgpack?source=hash-mapping + size: 80807 + timestamp: 1762504309629 +- conda: https://conda.anaconda.org/conda-forge/win-64/msgpack-python-1.1.2-py311h3fd045d_1.conda + sha256: 9883b64dea87c50e98fabc05719ff0fdc347f57d7bacda19bcd69b80d8c436d4 + md5: b0f2fb2eadce667ad09ca7d3ff868c71 + depends: + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/msgpack?source=hash-mapping + size: 87848 + timestamp: 1762504210288 +- conda: https://conda.anaconda.org/conda-forge/win-64/msgpack-python-1.1.2-py314h909e829_1.conda + sha256: 2ce1f564d5aa2e0637c03692baeea4ecf234c7fb2a43e7810c369e1b054d7a30 + md5: ad4584f884d029b02fc9eaf89afc5d9f + depends: + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/msgpack?source=hash-mapping + size: 88657 + timestamp: 1762504357246 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda + sha256: 3fde293232fa3fca98635e1167de6b7c7fda83caf24b9d6c91ec9eefb4f4d586 + md5: 47e340acb35de30501a76c7c799c41d7 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: X11 AND BSD-3-Clause + purls: [] + size: 891641 + timestamp: 1738195959188 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.5-ha32ae93_3.conda + sha256: 91cfb655a68b0353b2833521dc919188db3d8a7f4c64bea2c6a7557b24747468 + md5: 182afabe009dc78d8b73100255ee6868 + depends: + - libgcc >=13 + license: X11 AND BSD-3-Clause + purls: [] + size: 926034 + timestamp: 1738196018799 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-h0622a9a_3.conda + sha256: ea4a5d27ded18443749aefa49dc79f6356da8506d508b5296f60b8d51e0c4bd9 + md5: ced34dd9929f491ca6dab6a2927aff25 + depends: + - __osx >=10.13 + license: X11 AND BSD-3-Clause + purls: [] + size: 822259 + timestamp: 1738196181298 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.5-h5846eda_0.conda + sha256: 6ecc73db0e49143092c0934355ac41583a5d5a48c6914c5f6ca48e562d3a4b79 + md5: 02a888433d165c99bf09784a7b14d900 + license: X11 AND BSD-3-Clause + purls: [] + size: 823601 + timestamp: 1715195267791 +- 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 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.5-hb89a1cb_0.conda + sha256: 87d7cf716d9d930dab682cb57b3b8d3a61940b47d6703f3529a155c938a6990a + md5: b13ad5724ac9ae98b6b4fd87e4500ba4 + license: X11 AND BSD-3-Clause + purls: [] + size: 795131 + timestamp: 1715194898402 +- pypi: https://files.pythonhosted.org/packages/2b/60/c9a33361da8cde7c7760f091cd10467bc470634e4eea31c8bb70935b00a4/nh3-0.3.4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl + name: nh3 + version: 0.3.4 + sha256: 0d825722a1e8cbc87d7ca1e47ffb1d2a6cf343ad4c1b8465becf7cadcabcdfd0 + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/4a/57/a97955bc95960cfb1f0517043d60a121f4ba93fde252d4d9ffd3c2a9eead/nh3-0.3.4-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl + name: nh3 + version: 0.3.4 + sha256: d8bebcb20ab4b91858385cd98fe58046ec4a624275b45ef9b976475604f45b49 + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/73/4f/af8e9071d7464575a7316831938237ffc9d92d27f163dbdd964b1309cd9b/nh3-0.3.4-cp38-abi3-win_amd64.whl + name: nh3 + version: 0.3.4 + sha256: c10b1f0c741e257a5cb2978d6bac86e7c784ab20572724b20c6402c2e24bce75 + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/d6/b7/ec1cbc6b297a808c513f59f501656389623fc09ad6a58c640851289c7854/nh3-0.3.4-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + name: nh3 + version: 0.3.4 + sha256: 0961a27dc2057c38d0364cb05880e1997ae1c80220cbc847db63213720b8f304 + requires_python: '>=3.8' +- conda: https://conda.anaconda.org/conda-forge/linux-64/ninja-1.13.2-h171cf75_0.conda + sha256: 6f7d59dbec0a7b00bf5d103a4306e8886678b796ff2151b62452d4582b2a53fb + md5: b518e9e92493721281a60fa975bddc65 + depends: + - libstdcxx >=14 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 186323 + timestamp: 1763688260928 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ninja-1.13.2-hdc560ac_0.conda + sha256: 45fbc7c8c44681f5cefba1e5b26ca504a4485b000c5dfaa31cec0b7bc78d0de4 + md5: 8b5222a41b5d51fb1a5a2c514e770218 + depends: + - libstdcxx >=14 + - libgcc >=14 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 182666 + timestamp: 1763688214250 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ninja-1.12.0-h7728843_0.conda + sha256: dcc10cbea89b1846c76d7df06023f23866e794beb6412fffafb2fce6da19db05 + md5: 1ac079f6ecddd2c336f3acb7b371851f + depends: + - libcxx >=16 + license: Apache-2.0 + license_family: Apache + purls: [] + size: 124810 + timestamp: 1713204841161 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ninja-1.12.0-h2ffa867_0.conda + sha256: 634ff2cda6a77b9cd8935e748a1d5698f51f87f1a226638ddc95eb22f6a172ea + md5: 24e1b17a513393ee4e81e51fdab1fa93 + depends: + - libcxx >=16 + license: Apache-2.0 + license_family: Apache + purls: [] + size: 111688 + timestamp: 1713205253264 +- conda: https://conda.anaconda.org/conda-forge/win-64/ninja-1.13.2-h477610d_0.conda + sha256: e41a945c34a5f0bd2109b73a65486cd93023fa0a9bcba3ef98f9a3da40ba1180 + md5: 7ecb9f2f112c66f959d2bb7dbdb89b67 + depends: + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 309417 + timestamp: 1763688227932 +- conda: https://conda.anaconda.org/conda-forge/noarch/nlohmann_json-abi-3.12.0-h0f90c79_1.conda + sha256: 2a909594ca78843258e4bda36e43d165cda844743329838a29402823c8f20dec + md5: 59659d0213082bc13be8500bab80c002 + license: MIT + license_family: MIT + purls: [] + size: 4335 + timestamp: 1758194464430 +- conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + sha256: 4fa40e3e13fc6ea0a93f67dfc76c96190afd7ea4ffc1bac2612d954b42cdc3ee + md5: eb52d14a901e23c39e9e7b4a1a5c015f + depends: + - python >=3.10 + - setuptools + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/nodeenv?source=hash-mapping + size: 40866 + timestamp: 1766261270149 +- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.2.6-py310hefbff90_0.conda + sha256: 0ba94a61f91d67413e60fa8daa85627a8f299b5054b0eff8f93d26da83ec755e + md5: b0cea2c364bf65cd19e023040eeab05d + depends: + - __glibc >=2.17,<3.0.a0 + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - libgcc >=13 + - liblapack >=3.9.0,<4.0a0 + - libstdcxx >=13 + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/numpy?source=hash-mapping + size: 7893263 + timestamp: 1747545075833 +- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.2-py311h2e04523_1.conda + sha256: 2f9971a62316b9acb6ade749cebb59ffe750d1c2d99fe7061c6440589f6d3299 + md5: a8105076864776eceae69d64d30e24d7 + depends: + - python + - __glibc >=2.17,<3.0.a0 + - libstdcxx >=14 + - libgcc >=14 + - libblas >=3.9.0,<4.0a0 + - python_abi 3.11.* *_cp311 + - 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: 9385101 + timestamp: 1770098496391 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/numpy-2.2.6-py310h6e5608f_0.conda + sha256: d7234b9c45e4863c7d4c5221c1e91d69b0e0009464bf361c3fea47e64dc4adc2 + md5: 9e9f1f279eb02c41bda162a42861adc0 + depends: + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - libgcc >=13 + - liblapack >=3.9.0,<4.0a0 + - libstdcxx >=13 + - python >=3.10,<3.11.0a0 + - python >=3.10,<3.11.0a0 *_cpython + - python_abi 3.10.* *_cp310 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/numpy?source=hash-mapping + size: 6556655 + timestamp: 1747545077963 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/numpy-2.4.2-py311h669026d_1.conda + sha256: b40796e2b47878a38ffa5e76703a1d4d9f5fc09787cdf54fed9f4af8b66d1eb8 + md5: 6b411688a868a37d95abfb99ebc8b88e + depends: + - python + - libstdcxx >=14 + - libgcc >=14 + - python 3.11.* *_cpython + - liblapack >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - python_abi 3.11.* *_cp311 + - libblas >=3.9.0,<4.0a0 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/numpy?source=hash-mapping + size: 8462316 + timestamp: 1770098524745 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/numpy-2.4.3-py311h669026d_0.conda + sha256: 33e4d3e097a9d05e9e09d2895f4bd20f7fc93c8cb0df35da4716d0ba836a0d86 + md5: 23c6d37dec83159283cfeee4fceebf84 + depends: + - python + - python 3.11.* *_cpython + - libgcc >=14 + - libstdcxx >=14 + - libblas >=3.9.0,<4.0a0 + - liblapack >=3.9.0,<4.0a0 + - python_abi 3.11.* *_cp311 + - libcblas >=3.9.0,<4.0a0 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + purls: + - pkg:pypi/numpy?source=hash-mapping + size: 8464385 + timestamp: 1773839300790 +- conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-1.26.4-py310h4bfa8fc_0.conda + sha256: 914476e2d3273fdf9c0419a7bdcb7b31a5ec25949e4afbc847297ff3a50c62c8 + md5: cd6a2298387f558c9ea70ee73a189791 + depends: + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - libcxx >=16 + - liblapack >=3.9.0,<4.0a0 + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/numpy?source=hash-mapping + size: 6491938 + timestamp: 1707226191321 +- conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-1.26.4-py311hc43a94b_0.conda + sha256: dc9628197125ee1d02b2e7a859a769d26291d747ed79337309b8a9e67a8b8e00 + md5: bb02b8801d17265160e466cf8bbf28da + depends: + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - libcxx >=16 + - liblapack >=3.9.0,<4.0a0 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/numpy?source=hash-mapping + size: 7504319 + timestamp: 1707226235372 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-1.26.4-py310hd45542a_0.conda + sha256: e3078108a4973e73c813b89228f4bd8095ec58f96ca29f55d2e45a6223a9a1db + md5: 267ee89a3a0b8c8fa838a2353f9ea0c0 + depends: + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - libcxx >=16 + - liblapack >=3.9.0,<4.0a0 + - python >=3.10,<3.11.0a0 + - python >=3.10,<3.11.0a0 *_cpython + - python_abi 3.10.* *_cp310 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/numpy?source=hash-mapping + size: 5475744 + timestamp: 1707226187124 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-1.26.4-py311h7125741_0.conda + sha256: 160a52a01fea44fe9753a2ed22cf13d7b55c8a89ea0b8738546fdbf4795d6514 + md5: 3160b93669a0def35a7a8158ebb33816 + depends: + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - libcxx >=16 + - liblapack >=3.9.0,<4.0a0 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/numpy?source=hash-mapping + size: 6652352 + timestamp: 1707226297967 +- conda: https://conda.anaconda.org/conda-forge/win-64/numpy-2.2.6-py310h4987827_0.conda + sha256: 6f628e51763b86a535a723664e3aa1e38cb7147a2697f80b75c1980c1ed52f3e + md5: d2596785ac2cf5bab04e2ee9e5d04041 + depends: + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - liblapack >=3.9.0,<4.0a0 + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/numpy?source=hash-mapping + size: 6596153 + timestamp: 1747545352390 +- conda: https://conda.anaconda.org/conda-forge/win-64/numpy-2.4.2-py311h80b3fa1_1.conda + sha256: c5cd26fb28d92d6c3843b96489f433ef87d1866d03a746f7228230b74bef431a + md5: a824c6667179120c458beb9e9394932f + depends: + - python + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - python_abi 3.11.* *_cp311 + - libcblas >=3.9.0,<4.0a0 + - liblapack >=3.9.0,<4.0a0 + - libblas >=3.9.0,<4.0a0 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/numpy?source=hash-mapping + size: 7803678 + timestamp: 1770098404597 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda + sha256: 44c877f8af015332a5d12f5ff0fb20ca32f896526a7d0cdb30c769df1144fb5c + md5: f61eb8cd60ff9057122a3d338b99c00f + depends: + - __glibc >=2.17,<3.0.a0 + - ca-certificates + - libgcc >=14 + license: Apache-2.0 + license_family: Apache + purls: [] + size: 3164551 + timestamp: 1769555830639 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.1-h546c87b_1.conda + sha256: 7f8048c0e75b2620254218d72b4ae7f14136f1981c5eb555ef61645a9344505f + md5: 25f5885f11e8b1f075bccf4a2da91c60 + depends: + - ca-certificates + - libgcc >=14 + license: Apache-2.0 + license_family: Apache + purls: [] + size: 3692030 + timestamp: 1769557678657 +- conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.3.0-hd75f5a5_0.conda + sha256: d3889b0c89c2742e92e20f01e8f298b64c221df5d577c639b823a0bfe314e2e3 + md5: eb8c33aa7929a7714eab8b90c1d88afe + depends: + - ca-certificates + constrains: + - pyopenssl >=22.1 + license: Apache-2.0 + license_family: Apache + purls: [] + size: 2541802 + timestamp: 1714467068742 +- conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.6.1-hb6871ef_1.conda + sha256: e02e5639b0e4d6d4fcf0f3b082642844fb5a37316f5b0a1126c6271347462e90 + md5: 30bb8d08b99b9a7600d39efb3559fff0 + depends: + - __osx >=10.13 + - ca-certificates + license: Apache-2.0 + license_family: Apache + purls: [] + size: 2777136 + timestamp: 1769557662405 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.3.0-h0d3ecfb_0.conda + sha256: 51f9be8fe929c2bb3243cd0707b6dfcec27541f8284b4bd9b063c288fc46f482 + md5: 25b0e522c3131886a637e347b2ca0c0f + depends: + - ca-certificates + constrains: + - pyopenssl >=22.1 + license: Apache-2.0 + license_family: Apache + purls: [] + size: 2888226 + timestamp: 1714466346030 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.1-hd24854e_1.conda + sha256: 361f5c5e60052abc12bdd1b50d7a1a43e6a6653aab99a2263bf2288d709dcf67 + md5: f4f6ad63f98f64191c3e77c5f5f29d76 + depends: + - __osx >=11.0 + - ca-certificates + license: Apache-2.0 + license_family: Apache + purls: [] + size: 3104268 + timestamp: 1769556384749 +- conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.1-hf411b9b_1.conda + sha256: 53a5ad2e5553b8157a91bb8aa375f78c5958f77cb80e9d2ce59471ea8e5c0bd6 + md5: eb585509b815415bc964b2c7e11c7eb3 + depends: + - ca-certificates + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: Apache-2.0 + license_family: Apache + purls: [] + size: 9343023 + timestamp: 1769557547888 +- 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/noarch/packaging-26.0-pyhcf101f3_0.conda + sha256: c1fc0f953048f743385d31c468b4a678b3ad20caffdeaa94bed85ba63049fd58 + md5: b76541e68fea4d511b1ac46a28dcd2c6 + depends: + - python >=3.8 + - python + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/packaging?source=compressed-mapping + size: 72010 + timestamp: 1769093650580 +- conda: https://conda.anaconda.org/conda-forge/linux-64/patchelf-0.17.2-h58526e2_0.conda + sha256: eb355ac225be2f698e19dba4dcab7cb0748225677a9799e9cc8e4cadc3cb738f + md5: ba76a6a448819560b5f8b08a9c74f415 + depends: + - libgcc-ng >=7.5.0 + - libstdcxx-ng >=7.5.0 + license: GPL-3.0-or-later + license_family: GPL + purls: [] + size: 94048 + timestamp: 1673473024463 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/patchelf-0.17.2-h884eca8_0.conda + sha256: 8b98158f36a7a92013a1982ab7a60947151350ac5c513c1d1575825d0fa52518 + md5: bbd8dee69c4ac2e2d07bca100b8fcc31 + depends: + - libgcc-ng >=7.5.0 + - libstdcxx-ng >=7.5.0 + license: GPL-3.0-or-later + license_family: GPL + purls: [] + size: 101306 + timestamp: 1673473812166 +- conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.0.4-pyhd8ed1ab_0.conda + sha256: 29ea20d0faf20374fcd61c25f6d32fb8e9a2c786a7f1473a0c3ead359470fbe1 + md5: 2908273ac396d2cd210a8127f5f1c0d6 + depends: + - python >=3.10 + license: MPL-2.0 + license_family: MOZILLA + purls: + - pkg:pypi/pathspec?source=hash-mapping + size: 53739 + timestamp: 1769677743677 +- pypi: https://files.pythonhosted.org/packages/54/16/12b82f791c7f50ddec566873d5bdd245baa1491bac11d15ffb98aecc8f8b/pefile-2024.8.26-py3-none-any.whl + name: pefile + version: 2024.8.26 + sha256: 76f8b485dcd3b1bb8166f1128d395fa3d87af26360c2358fb75b80019b957c6f + requires_python: '>=3.6.0' +- conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda + sha256: 8e1497814a9997654ed7990a79c054ea5a42545679407acbc6f7e809c73c9120 + md5: 67bdec43082fd8a9cffb9484420b39a2 + depends: + - python >=3.10,<3.13.0a0 + - setuptools + - wheel + license: MIT + license_family: MIT + purls: + - pkg:pypi/pip?source=compressed-mapping + size: 1181790 + timestamp: 1770270305795 +- conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-unix_hf108a03_0.conda + sha256: c84a62f421f3ba388df06df7f414d7b568ad4bc3c33a7799b3405f213a3b1ff5 + md5: 07b709969aa53039501c5960e45794b8 + depends: + - __unix + - python >=3.8 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 7034 + timestamp: 1763572165675 +- conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.10-win_hba80fca_0.conda + sha256: c0399f79f0656df7e265ae53630e08cad2d2203a2f39181ff1a68b3b39466d0d + md5: 6dea6b7cca5948b0cfd6eeb5ddecce67 + depends: + - __win + - python >=3.8 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 7042 + timestamp: 1763572121812 +- conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.12.1.2-pyhd8ed1ab_0.conda + sha256: 353fd5a2c3ce31811a6272cd328874eb0d327b1eafd32a1e19001c4ad137ad3a + md5: dc702b2fae7ebe770aff3c83adb16b63 + depends: + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pkginfo?source=hash-mapping + size: 30536 + timestamp: 1739984682585 +- conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda + sha256: 0289f0a38337ee201d984f8f31f11f6ef076cfbbfd0ab9181d12d9d1d099bf46 + md5: 82c1787f2a65c0155ef9652466ee98d6 + depends: + - python >=3.10 + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/platformdirs?source=compressed-mapping + size: 25646 + timestamp: 1773199142345 +- conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + sha256: e14aafa63efa0528ca99ba568eaf506eb55a0371d12e6250aaaa61718d2eb62e + md5: d7585b6550ad04c8c5e21097ada2888e + depends: + - python >=3.9 + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/pluggy?source=compressed-mapping + size: 25877 + timestamp: 1764896838868 +- conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda + sha256: 5b81b7516d4baf43d0c185896b245fa7384b25dc5615e7baa504b7fa4e07b706 + md5: 7f3ac694319c7eaf81a0325d6405e974 + depends: + - cfgv >=2.0.0 + - identify >=1.0.0 + - nodeenv >=0.11.1 + - python >=3.10 + - pyyaml >=5.1 + - virtualenv >=20.10.0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pre-commit?source=compressed-mapping + size: 200827 + timestamp: 1765937577534 +- conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-11-hc364b38_1.conda + sha256: 9e7fe12f727acd2787fb5816b2049cef4604b7a00ad3e408c5e709c298ce8bf1 + md5: f0599959a2447c1e544e216bddf393fa + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 14671 + timestamp: 1752769938071 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pycosat-0.6.6-py310h7c4b9e2_3.conda + sha256: 86d343a2122b55394fda137eaf5461b6e91ac459ffc6f5b4c78f69f00ffd1a12 + md5: 14ab9efb46276ca0d751c942381e90dd + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pycosat?source=hash-mapping + size: 84754 + timestamp: 1757744718942 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pycosat-0.6.6-py311h49ec1c0_3.conda + sha256: 61c07e45a0a0c7a2b0dc986a65067fc2b00aba51663b7b05d4449c7862d7a390 + md5: 77c1b47af5775a813193f7870be8644a + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pycosat?source=hash-mapping + size: 88491 + timestamp: 1757744790912 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pycosat-0.6.6-py314h5bd0f2a_3.conda + sha256: ccef6174b89815de1ede61b3b20ebccfe301865f2954d789e0b5c1e52dd45f91 + md5: be49bb746ad2cd2ba6737b4afd6cf32a + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - python >=3.14.0rc2,<3.15.0a0 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pycosat?source=hash-mapping + size: 88644 + timestamp: 1757744868118 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pycosat-0.6.6-py310h5b55623_3.conda + sha256: 8d9511499803b3899273964a9a571760de5bd7ad4d90cbdf9a16946fc1c60605 + md5: 49ad177a7adc4c714b2725c36f8b1f45 + depends: + - libgcc >=14 + - python >=3.10,<3.11.0a0 + - python >=3.10,<3.11.0a0 *_cpython + - python_abi 3.10.* *_cp310 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pycosat?source=hash-mapping + size: 86257 + timestamp: 1757744805289 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pycosat-0.6.6-py311h19352d5_3.conda + sha256: 792ef42d5691757c087c2214e03e6e5cd1470075bc99c53a62067690345f80be + md5: 8b3741984919ba072ef6d1243e543336 + depends: + - libgcc >=14 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pycosat?source=hash-mapping + size: 88731 + timestamp: 1757744856802 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pycosat-0.6.6-py314h51f160d_3.conda + sha256: 20c29d8283581ed5fece2ea5ebac9c1f78756ff523d9c866b50110d8fadc3b7f + md5: 180a289ef4d6ce81588a13f55a4b7238 + depends: + - libgcc >=14 + - python >=3.14.0rc2,<3.15.0a0 + - python >=3.14.0rc2,<3.15.0a0 *_cp314 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pycosat?source=hash-mapping + size: 89501 + timestamp: 1757744787708 +- conda: https://conda.anaconda.org/conda-forge/osx-64/pycosat-0.6.6-py310h6729b98_0.conda + sha256: c8ce26a91bd19ab83f8fb7e2f8ada1de799453b519ee156f59aa901146f353d8 + md5: 89b601f80d076bf8053eea906293353c + depends: + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pycosat?source=hash-mapping + size: 84654 + timestamp: 1696356173413 +- conda: https://conda.anaconda.org/conda-forge/osx-64/pycosat-0.6.6-py311h2725bcf_0.conda + sha256: 1899b863919c949d38634dbdaec7af2ddb52326a496dd68751ab4f4fe0e8f36a + md5: 47b4652f8a7e6222786663c757815dd5 + depends: + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pycosat?source=hash-mapping + size: 88031 + timestamp: 1696356171531 +- conda: https://conda.anaconda.org/conda-forge/osx-64/pycosat-0.6.6-py314h03d016b_3.conda + sha256: 6e361e86d25f9ca4b923c85cb0fb34c581b68199d9787df433260722e8101ab7 + md5: a4e0b3801e6673059cea365dc47e4a6e + depends: + - __osx >=10.13 + - python >=3.14.0rc2,<3.15.0a0 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pycosat?source=hash-mapping + size: 96705 + timestamp: 1757744863538 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pycosat-0.6.6-py310h2aa6e3c_0.conda + sha256: 43fc36a584cc9db9cbcd0bee62875ca7702e68fd1df1f35db87f3a14098bb8bc + md5: 3a048bfd19ef0f4e1d6efd3f821c3988 + depends: + - python >=3.10,<3.11.0a0 + - python >=3.10,<3.11.0a0 *_cpython + - python_abi 3.10.* *_cp310 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pycosat?source=hash-mapping + size: 82535 + timestamp: 1696356406059 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pycosat-0.6.6-py311heffc1b2_0.conda + sha256: 4451971678bbc4fb314201f786c5c3640d429985d195e7d940bfd7d33a384560 + md5: d60b2f87d7b8dd1623fb1baf91a0e311 + depends: + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pycosat?source=hash-mapping + size: 85652 + timestamp: 1696356197481 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pycosat-0.6.6-py314hb84d1df_3.conda + sha256: ec919254bca5ba7ef89ac1284582aa91297b89c3b640feda05a3cab0a0402db2 + md5: b23019984b3399dada68581c20e6ef85 + depends: + - __osx >=11.0 + - python >=3.14.0rc2,<3.15.0a0 + - python >=3.14.0rc2,<3.15.0a0 *_cp314 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pycosat?source=hash-mapping + size: 92986 + timestamp: 1757744788529 +- conda: https://conda.anaconda.org/conda-forge/win-64/pycosat-0.6.6-py310h29418f3_3.conda + sha256: e81fa9c4554907d3051f4fe6166d66949075bd6fac01f284902f73f4ac9da73e + md5: c51140b7978bf63c441af87be1f6fedf + depends: + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pycosat?source=hash-mapping + size: 76648 + timestamp: 1757744973237 +- conda: https://conda.anaconda.org/conda-forge/win-64/pycosat-0.6.6-py311h3485c13_3.conda + sha256: f2968e9d6516d7df4c678ce99e922285f244bfaf65069fb2cb3d307b4661f889 + md5: b0cdbb8f4ecd5e1750400ef8bbcb390b + depends: + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pycosat?source=hash-mapping + size: 79248 + timestamp: 1757744865552 +- conda: https://conda.anaconda.org/conda-forge/win-64/pycosat-0.6.6-py314h5a2d7ad_3.conda + sha256: e14a8c506e699c968596f1a07e925d63dcc49ee9f3623c4c8a5541ad186e9071 + md5: 4e6be0e1a7a9cd7dde994137b8ebd5cf + depends: + - python >=3.14.0rc2,<3.15.0a0 + - python_abi 3.14.* *_cp314 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pycosat?source=hash-mapping + size: 79551 + timestamp: 1757744726713 +- conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + sha256: 79db7928d13fab2d892592223d7570f5061c192f27b9febd1a418427b719acc6 + md5: 12c566707c80111f9799308d9e265aef + depends: + - python >=3.9 + - python + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/pycparser?source=hash-mapping + size: 110100 + timestamp: 1733195786147 +- conda: https://conda.anaconda.org/conda-forge/noarch/pyelftools-0.32-pyh707e725_1.conda + sha256: de3a334388959397ba7b69ee92d5dfaa0c1bd6a7ffcf49c3c4de2ac045c69d28 + md5: eae78c632c980c396cf6f711cf515c3a + depends: + - __unix + - python >=3.9 + license: Unlicense + purls: + - pkg:pypi/pyelftools?source=hash-mapping + size: 149336 + timestamp: 1744148364068 +- pypi: https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl + name: pygments + version: 2.20.0 + sha256: 81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176 + requires_dist: + - colorama>=0.4.6 ; extra == 'windows-terminal' + requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/noarch/pyopenssl-25.1.0-pyhd8ed1ab_0.conda + sha256: 0d7a8ebdfff0f579a64a95a94cf280ec2889d6c52829a9dbbd3ea9eef02c2f6f + md5: 63d6393b45f33dc0782d73f6d8ae36a0 + depends: + - cryptography >=41.0.5,<46 + - python >=3.9 + - typing-extensions >=4.9 + - typing_extensions >=4.9 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/pyopenssl?source=hash-mapping + size: 123256 + timestamp: 1747560884456 +- pypi: https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl + name: pyproject-hooks + version: 1.2.0 + sha256: 9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913 + requires_python: '>=3.7' +- conda: https://conda.anaconda.org/conda-forge/noarch/pyproject-metadata-0.11.0-pyhd8ed1ab_0.conda + sha256: 7e709bde682104c241674f8005fd560d7ea8599458c94d03ed51ef8a4ae7d737 + md5: cd6dae6c673c8f12fe7267eac3503961 + depends: + - packaging >=23.2 + - python >=3.10 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyproject-metadata?source=hash-mapping + size: 25200 + timestamp: 1770672303277 +- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyh09c184e_7.conda + sha256: d016e04b0e12063fbee4a2d5fbb9b39a8d191b5a0042f0b8459188aedeabb0ca + md5: e2fd202833c4a981ce8a65974fe4abd1 + depends: + - __win + - python >=3.9 + - win_inet_pton + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/pysocks?source=hash-mapping + size: 21784 + timestamp: 1733217448189 +- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda + sha256: ba3b032fa52709ce0d9fd388f63d330a026754587a2f461117cac9ab73d8d0d8 + md5: 461219d1a5bd61342293efa2c0c90eac + depends: + - __unix + - python >=3.9 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/pysocks?source=hash-mapping + size: 21085 + timestamp: 1733217331982 +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.10.20-h3c07f61_0_cpython.conda + sha256: 8ff2ce308faf2588b69c65b120293f59a8f2577b772b34df4e817d220b09e081 + md5: 5d4e2b00d99feacd026859b7fa239dc0 + depends: + - __glibc >=2.17,<3.0.a0 + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-64 >=2.36.1 + - libexpat >=2.7.4,<3.0a0 + - libffi >=3.4,<4.0a0 + - libgcc >=14 + - liblzma >=5.8.2,<6.0a0 + - libnsl >=2.0.1,<2.1.0a0 + - libsqlite >=3.51.2,<4.0a0 + - libuuid >=2.41.3,<3.0a0 + - libxcrypt >=4.4.36 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.5,<4.0a0 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + constrains: + - python_abi 3.10.* *_cp310 + license: Python-2.0 + purls: [] + size: 25455342 + timestamp: 1772729810280 +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.11.15-hd63d673_0_cpython.conda + sha256: bf6a32c69889d38482436a786bea32276756cedf0e9805cc856ffd088e8d00f0 + md5: a5ebcefec0c12a333bcd6d7bf3bddc1f + depends: + - __glibc >=2.17,<3.0.a0 + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-64 >=2.36.1 + - libexpat >=2.7.4,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - liblzma >=5.8.2,<6.0a0 + - libnsl >=2.0.1,<2.1.0a0 + - libsqlite >=3.51.2,<4.0a0 + - libuuid >=2.41.3,<3.0a0 + - libxcrypt >=4.4.36 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.5,<4.0a0 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + constrains: + - python_abi 3.11.* *_cp311 + license: Python-2.0 + purls: [] + size: 30949404 + timestamp: 1772730362552 +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.3-h32b2ec7_101_cp314.conda + build_number: 101 + sha256: cb0628c5f1732f889f53a877484da98f5a0e0f47326622671396fb4f2b0cd6bd + md5: c014ad06e60441661737121d3eae8a60 + depends: + - __glibc >=2.17,<3.0.a0 + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-64 >=2.36.1 + - libexpat >=2.7.3,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - liblzma >=5.8.2,<6.0a0 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.51.2,<4.0a0 + - libuuid >=2.41.3,<3.0a0 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.5,<4.0a0 + - python_abi 3.14.* *_cp314 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - zstd >=1.5.7,<1.6.0a0 + license: Python-2.0 + purls: [] + size: 36702440 + timestamp: 1770675584356 + python_site_packages_path: lib/python3.14/site-packages +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.10.20-h28be5d3_0_cpython.conda + sha256: 2f16794d69e058404cca633021b284e70253dfb76e4b314d9dbd448aa0354e84 + md5: 5d61c9a2acf7c675f7ae5f6cf51ffb0b + depends: + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-aarch64 >=2.36.1 + - libexpat >=2.7.4,<3.0a0 + - libffi >=3.4,<4.0a0 + - libgcc >=14 + - liblzma >=5.8.2,<6.0a0 + - libnsl >=2.0.1,<2.1.0a0 + - libsqlite >=3.51.2,<4.0a0 + - libuuid >=2.41.3,<3.0a0 + - libxcrypt >=4.4.36 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.5,<4.0a0 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + constrains: + - python_abi 3.10.* *_cp310 + license: Python-2.0 + purls: [] + size: 13234644 + timestamp: 1772728813900 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.11.15-h91f4b29_0_cpython.conda + sha256: da3aa4c63af904d38c2e0b6ceecfa539d60c2653ac3cff7cae79d87298dc4fb0 + md5: bb09184ea3313703da05516cd730e8f8 + depends: + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-aarch64 >=2.36.1 + - libexpat >=2.7.4,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - liblzma >=5.8.2,<6.0a0 + - libnsl >=2.0.1,<2.1.0a0 + - libsqlite >=3.51.2,<4.0a0 + - libuuid >=2.41.3,<3.0a0 + - libxcrypt >=4.4.36 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.5,<4.0a0 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + constrains: + - python_abi 3.11.* *_cp311 + license: Python-2.0 + purls: [] + size: 14306513 + timestamp: 1772728906052 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.3-hb06a95a_101_cp314.conda + build_number: 101 + sha256: 87e9dff5646aba87cecfbc08789634c855871a7325169299d749040b0923a356 + md5: 205011b36899ff0edf41b3db0eda5a44 + depends: + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-aarch64 >=2.36.1 + - libexpat >=2.7.3,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - liblzma >=5.8.2,<6.0a0 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.51.2,<4.0a0 + - libuuid >=2.41.3,<3.0a0 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.5,<4.0a0 + - python_abi 3.14.* *_cp314 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - zstd >=1.5.7,<1.6.0a0 + license: Python-2.0 + purls: [] + size: 37305578 + timestamp: 1770674395875 + python_site_packages_path: lib/python3.14/site-packages +- conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.10.14-h00d2728_0_cpython.conda + sha256: 00c1de2d46ede26609ef4e84a44b83be7876ba6a0215b7c83bff41a0656bf694 + md5: 0a1cddc4382c5c171e791c70740546dd + depends: + - bzip2 >=1.0.8,<2.0a0 + - libffi >=3.4,<4.0a0 + - libsqlite >=3.45.2,<4.0a0 + - libzlib >=1.2.13,<2.0.0a0 + - ncurses >=6.4.20240210,<7.0a0 + - openssl >=3.2.1,<4.0a0 + - readline >=8.2,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - xz >=5.2.6,<6.0a0 + constrains: + - python_abi 3.10.* *_cp310 + license: Python-2.0 + purls: [] + size: 11890228 + timestamp: 1710940046031 +- conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.11.8-h9f0c242_0_cpython.conda + sha256: 645dad20b46041ecd6a85eccbb3291fa1ad7921eea065c0081efff78c3d7e27a + md5: 22bda10a0f425564a538aed9a0e8a9df + depends: + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.5.0,<3.0a0 + - libffi >=3.4,<4.0a0 + - libsqlite >=3.45.1,<4.0a0 + - libzlib >=1.2.13,<2.0.0a0 + - ncurses >=6.4,<7.0a0 + - openssl >=3.2.1,<4.0a0 + - readline >=8.2,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - xz >=5.2.6,<6.0a0 + constrains: + - python_abi 3.11.* *_cp311 + license: Python-2.0 + purls: [] + size: 14067894 + timestamp: 1708117836907 +- conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.14.3-h4f44bb5_101_cp314.conda + build_number: 101 + sha256: f64e357aa0168a201c9b3eedf500d89a8550d6631d26a95590b12de61f8fd660 + md5: 030ec23658b941438ac42303aff0db2b + depends: + - __osx >=10.13 + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.7.3,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - liblzma >=5.8.2,<6.0a0 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.51.2,<4.0a0 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.5,<4.0a0 + - python_abi 3.14.* *_cp314 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - zstd >=1.5.7,<1.6.0a0 + license: Python-2.0 + purls: [] + size: 14387288 + timestamp: 1770676578632 + python_site_packages_path: lib/python3.14/site-packages +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.10.14-h2469fbe_0_cpython.conda + sha256: 454d609fe25daedce9e886efcbfcadad103ed0362e7cb6d2bcddec90b1ecd3ee + md5: 4ae999c8227c6d8c7623d32d51d25ea9 + depends: + - bzip2 >=1.0.8,<2.0a0 + - libffi >=3.4,<4.0a0 + - libsqlite >=3.45.2,<4.0a0 + - libzlib >=1.2.13,<2.0.0a0 + - ncurses >=6.4.20240210,<7.0a0 + - openssl >=3.2.1,<4.0a0 + - readline >=8.2,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - xz >=5.2.6,<6.0a0 + constrains: + - python_abi 3.10.* *_cp310 + license: Python-2.0 + purls: [] + size: 12336005 + timestamp: 1710939659384 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.11.8-hdf0ec26_0_cpython.conda + sha256: 6c9bbac137759e013e6a50593c7cf10a06032fcb1ef3a994c598c7a95e73a8e1 + md5: 8f4076d960f17f19ae8b2f66727ea1c6 + depends: + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.5.0,<3.0a0 + - libffi >=3.4,<4.0a0 + - libsqlite >=3.45.1,<4.0a0 + - libzlib >=1.2.13,<2.0.0a0 + - ncurses >=6.4,<7.0a0 + - openssl >=3.2.1,<4.0a0 + - readline >=8.2,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - xz >=5.2.6,<6.0a0 + constrains: + - python_abi 3.11.* *_cp311 + license: Python-2.0 + purls: [] + size: 14623079 + timestamp: 1708116925163 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.14.3-h4c637c5_101_cp314.conda + build_number: 101 + sha256: fccce2af62d11328d232df9f6bbf63464fd45f81f718c661757f9c628c4378ce + md5: 753c8d0447677acb7ddbcc6e03e82661 + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.7.3,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - liblzma >=5.8.2,<6.0a0 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.51.2,<4.0a0 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.5,<4.0a0 + - python_abi 3.14.* *_cp314 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - zstd >=1.5.7,<1.6.0a0 + license: Python-2.0 + purls: [] + size: 13522698 + timestamp: 1770675365241 + python_site_packages_path: lib/python3.14/site-packages +- conda: https://conda.anaconda.org/conda-forge/win-64/python-3.10.20-hc20f281_0_cpython.conda + sha256: e71595dd281a9902d7b84f545f16d7d4c0fb62cc6816431301f8f4870c94dc8c + md5: 6c18c24d33a7ac8a4f81c68b8eb8581b + depends: + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.7.4,<3.0a0 + - libffi >=3.4,<4.0a0 + - liblzma >=5.8.2,<6.0a0 + - libsqlite >=3.51.2,<4.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.5,<4.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + constrains: + - python_abi 3.10.* *_cp310 + license: Python-2.0 + purls: [] + size: 16028082 + timestamp: 1772728853200 +- conda: https://conda.anaconda.org/conda-forge/win-64/python-3.11.15-h0159041_0_cpython.conda + sha256: a1f1031088ce69bc99c82b95980c1f54e16cbd5c21f042e9c1ea25745a8fc813 + md5: d09dbf470b41bca48cbe6a78ba1e009b + depends: + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.7.4,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - liblzma >=5.8.2,<6.0a0 + - libsqlite >=3.51.2,<4.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.5,<4.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + constrains: + - python_abi 3.11.* *_cp311 + license: Python-2.0 + purls: [] + size: 18416208 + timestamp: 1772728847666 +- conda: https://conda.anaconda.org/conda-forge/win-64/python-3.14.3-h4b44e0e_101_cp314.conda + build_number: 101 + sha256: 3f99d83bfd95b9bdae64a42a1e4bf5131dc20b724be5ac8a9a7e1ac2c0f006d7 + md5: 7ec2be7eaf59f83f3e5617665f3fbb2e + depends: + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.7.3,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - liblzma >=5.8.2,<6.0a0 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.51.2,<4.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.5,<4.0a0 + - python_abi 3.14.* *_cp314 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - zstd >=1.5.7,<1.6.0a0 + license: Python-2.0 + purls: [] + size: 18273230 + timestamp: 1770675442998 + python_site_packages_path: Lib/site-packages +- conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda + sha256: 5a70a9cbcf48be522c2b82df8c7a57988eed776f159142b0d30099b61f31a35e + md5: f2e88fc463b249bc1f40d9ca969d9b5e + depends: + - python >=3.10 + - filelock >=3.15.4 + - platformdirs <5,>=4.3.6 + - python + license: MIT + purls: + - pkg:pypi/python-discovery?source=compressed-mapping + size: 34137 + timestamp: 1774605818480 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.10-8_cp310.conda + build_number: 8 + sha256: 7ad76fa396e4bde336872350124c0819032a9e8a0a40590744ff9527b54351c1 + md5: 05e00f3b21e88bb3d658ac700b2ce58c + constrains: + - python 3.10.* *_cpython + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 6999 + timestamp: 1752805924192 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda + build_number: 8 + sha256: fddf123692aa4b1fc48f0471e346400d9852d96eeed77dbfdd746fa50a8ff894 + md5: 8fcb6b0e2161850556231336dae58358 + constrains: + - python 3.11.* *_cpython + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 7003 + timestamp: 1752805919375 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + build_number: 8 + sha256: ad6d2e9ac39751cc0529dd1566a26751a0bf2542adb0c232533d32e176e21db5 + md5: 0539938c55b6b1a59b560e843ad864a4 + constrains: + - python 3.14.* *_cp314 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 6989 + timestamp: 1752805904792 +- pypi: https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl + name: pywin32-ctypes + version: 0.2.3 + sha256: 8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8 + requires_python: '>=3.6' +- conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py310h3406613_1.conda + sha256: f23de6cc72541c6081d3d27482dbc9fc5dd03be93126d9155f06d0cf15d6e90e + md5: 2160894f57a40d2d629a34ee8497795f + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyyaml?source=hash-mapping + size: 176522 + timestamp: 1770223379599 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py311h3778330_1.conda + sha256: c9a6cd2c290d7c3d2b30ea34a0ccda30f770e8ddb2937871f2c404faf60d0050 + md5: a24add9a3bababee946f3bc1c829acfe + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyyaml?source=compressed-mapping + size: 206190 + timestamp: 1770223702917 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py314h67df5f8_1.conda + sha256: b318fb070c7a1f89980ef124b80a0b5ccf3928143708a85e0053cde0169c699d + md5: 2035f68f96be30dc60a5dfd7452c7941 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyyaml?source=compressed-mapping + size: 202391 + timestamp: 1770223462836 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py310h2d8da20_1.conda + sha256: 8acefeb5cc4bcf835f33e45b5cc8b350e738b4954f68c3d8051426e851ca2806 + md5: 7e1a74e779e08e3504230f8216be618b + depends: + - libgcc >=14 + - python >=3.10,<3.11.0a0 + - python >=3.10,<3.11.0a0 *_cpython + - python_abi 3.10.* *_cp310 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyyaml?source=hash-mapping + size: 171618 + timestamp: 1770223419125 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py311h164a683_1.conda + sha256: e3175f507827cd575b5a7b7b50058cd253977f8286079cb3a6bf0aeaa878071b + md5: 7e1888f50cc191b7817848dbf6f90590 + depends: + - libgcc >=14 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyyaml?source=hash-mapping + size: 201473 + timestamp: 1770223445971 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py314h807365f_1.conda + sha256: 496b5e65dfdd0aaaaa5de0dcaaf3bceea00fcb4398acf152f89e567c82ec1046 + md5: 9ae2c92975118058bd720e9ba2bb7c58 + depends: + - libgcc >=14 + - python >=3.14,<3.15.0a0 + - python >=3.14,<3.15.0a0 *_cp314 + - python_abi 3.14.* *_cp314 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyyaml?source=hash-mapping + size: 195678 + timestamp: 1770223441816 +- conda: https://conda.anaconda.org/conda-forge/osx-64/pyyaml-6.0.1-py310h6729b98_1.conda + sha256: 00567f2cb2d1c8fede8fe7727f7bbd1c38cbca886814d612e162d5c936d8db1b + md5: d964cec3e7972e44bc4a328134b9eaf1 + depends: + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyyaml?source=hash-mapping + size: 160097 + timestamp: 1695373947773 +- conda: https://conda.anaconda.org/conda-forge/osx-64/pyyaml-6.0.1-py311h2725bcf_1.conda + sha256: 8ce2ba443414170a2570514d0ce6d03625a847e91af9763d48dc58c338e6f7f3 + md5: 9283f991b5e5856a99f8aabba9927df5 + depends: + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyyaml?source=hash-mapping + size: 188606 + timestamp: 1695373840022 +- conda: https://conda.anaconda.org/conda-forge/osx-64/pyyaml-6.0.3-py314h10d0514_1.conda + sha256: aef010899d642b24de6ccda3bc49ef008f8fddf7bad15ebce9bdebeae19a4599 + md5: ebd224b733573c50d2bfbeacb5449417 + depends: + - __osx >=10.13 + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyyaml?source=hash-mapping + size: 191947 + timestamp: 1770226344240 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyyaml-6.0.1-py310h2aa6e3c_1.conda + sha256: 7b8668cd86d2421c62ec241f840d84a600b854afc91383a509bbb60ba907aeec + md5: 0e7ccdd121ce7b486f1de7917178387c + depends: + - python >=3.10,<3.11.0a0 + - python >=3.10,<3.11.0a0 *_cpython + - python_abi 3.10.* *_cp310 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyyaml?source=hash-mapping + size: 158641 + timestamp: 1695373859696 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyyaml-6.0.1-py311heffc1b2_1.conda + sha256: b155f5c27f0e2951256774628c4b91fdeee3267018eef29897a74e3d1316c8b0 + md5: d310bfbb8230b9175c0cbc10189ad804 + depends: + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyyaml?source=hash-mapping + size: 187795 + timestamp: 1695373829282 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyyaml-6.0.3-py314h6e9b3f0_1.conda + sha256: 95f385f9606e30137cf0b5295f63855fd22223a4cf024d306cf9098ea1c4a252 + md5: dcf51e564317816cb8d546891019b3ab + depends: + - __osx >=11.0 + - python >=3.14,<3.15.0a0 + - python >=3.14,<3.15.0a0 *_cp314 + - python_abi 3.14.* *_cp314 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyyaml?source=hash-mapping + size: 189475 + timestamp: 1770223788648 +- conda: https://conda.anaconda.org/conda-forge/win-64/pyyaml-6.0.3-py310hdb0e946_1.conda + sha256: 3b643534d7b029073fd0ec1548a032854bb45391bc51dfdf9fec8d327e9f688d + md5: 463566b14434383e34e366143808b4b7 + depends: + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyyaml?source=hash-mapping + size: 157282 + timestamp: 1770223476842 +- conda: https://conda.anaconda.org/conda-forge/win-64/pyyaml-6.0.3-py311h3f79411_1.conda + sha256: 301c3ba100d25cd5ae37895988ee3ab986210d4d972aa58efed948fbe857773d + md5: a0153c033dc55203e11d1cac8f6a9cf2 + depends: + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyyaml?source=hash-mapping + size: 187108 + timestamp: 1770223467913 +- conda: https://conda.anaconda.org/conda-forge/win-64/pyyaml-6.0.3-py314h2359020_1.conda + sha256: a2aff34027aa810ff36a190b75002d2ff6f9fbef71ec66e567616ac3a679d997 + md5: 0cd9b88826d0f8db142071eb830bce56 + depends: + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyyaml?source=compressed-mapping + size: 181257 + timestamp: 1770223460931 +- conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda + sha256: 12ffde5a6f958e285aa22c191ca01bbd3d6e710aa852e00618fa6ddc59149002 + md5: d7d95fc8287ea7bf33e0e7116d2b95ec + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - ncurses >=6.5,<7.0a0 + license: GPL-3.0-only + license_family: GPL + purls: [] + size: 345073 + timestamp: 1765813471974 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda + sha256: fe695f9d215e9a2e3dd0ca7f56435ab4df24f5504b83865e3d295df36e88d216 + md5: 3d49cad61f829f4f0e0611547a9cda12 + depends: + - libgcc >=14 + - ncurses >=6.5,<7.0a0 + license: GPL-3.0-only + license_family: GPL + purls: [] + size: 357597 + timestamp: 1765815673644 +- conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h7cca4af_2.conda + sha256: 53017e80453c4c1d97aaf78369040418dea14cf8f46a2fa999f31bd70b36c877 + md5: 342570f8e02f2f022147a7f841475784 + depends: + - ncurses >=6.5,<7.0a0 + license: GPL-3.0-only + license_family: GPL + purls: [] + size: 256712 + timestamp: 1740379577668 +- conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda + sha256: 4614af680aa0920e82b953fece85a03007e0719c3399f13d7de64176874b80d5 + md5: eefd65452dfe7cce476a519bece46704 + depends: + - __osx >=10.13 + - ncurses >=6.5,<7.0a0 + license: GPL-3.0-only + license_family: GPL + purls: [] + size: 317819 + timestamp: 1765813692798 +- 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/osx-arm64/readline-8.3-h46df422_0.conda + sha256: a77010528efb4b548ac2a4484eaf7e1c3907f2aec86123ed9c5212ae44502477 + md5: f8381319127120ce51e081dce4865cf4 + depends: + - __osx >=11.0 + - ncurses >=6.5,<7.0a0 + license: GPL-3.0-only + license_family: GPL + purls: [] + size: 313930 + timestamp: 1765813902568 +- pypi: https://files.pythonhosted.org/packages/e1/67/921ec3024056483db83953ae8e48079ad62b92db7880013ca77632921dd0/readme_renderer-44.0-py3-none-any.whl + name: readme-renderer + version: '44.0' + sha256: 2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151 + requires_dist: + - nh3>=0.2.14 + - docutils>=0.21.2 + - pygments>=2.5.1 + - cmarkgfm>=0.8.0 ; extra == 'md' + requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-14.2.5.post0-hb9d3cd8_0.conda + sha256: a1973f41a6b956f1305f9aaefdf14b2f35a8c9615cfe5f143f1784ed9aa6bf47 + md5: 69fbc0a9e42eb5fe6733d2d60d818822 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 34194 + timestamp: 1731925834928 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/reproc-14.2.5.post0-h86ecc28_0.conda + sha256: 3bbcfd61da8ab71c0b7b5bbff471669f64e6a3fb759411a46a2d4fd31a9642cc + md5: 70b14ba118c2c19b240a39577b3e607a + depends: + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 36102 + timestamp: 1745309589538 +- conda: https://conda.anaconda.org/conda-forge/osx-64/reproc-14.2.5.post0-h6e16a3a_0.conda + sha256: dda2a8bc1bf16b563b74c2a01dccea657bda573b0c45e708bfeee01c208bcbaf + md5: eda18d4a7dce3831016086a482965345 + depends: + - __osx >=10.13 + license: MIT + license_family: MIT + purls: [] + size: 31749 + timestamp: 1731926270954 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/reproc-14.2.5.post0-h5505292_0.conda + sha256: a5f0dbfa8099a3d3c281ea21932b6359775fd8ce89acc53877a6ee06f50642bc + md5: f1d129089830365d9dac932c4dd8c675 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 32023 + timestamp: 1731926255834 +- conda: https://conda.anaconda.org/conda-forge/win-64/reproc-14.2.5.post0-h2466b09_0.conda + sha256: 112dee79da4f55de91f029dd9808f4284bc5e0cf0c4d308d4cec3381bf5bc836 + md5: c3ca4c18c99a3b9832e11b11af227713 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + license: MIT + license_family: MIT + purls: [] + size: 37058 + timestamp: 1731926140985 +- conda: https://conda.anaconda.org/conda-forge/linux-64/reproc-cpp-14.2.5.post0-h5888daf_0.conda + sha256: 568485837b905b1ea7bdb6e6496d914b83db57feda57f6050d5a694977478691 + md5: 828302fca535f9cfeb598d5f7c204323 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libstdcxx >=13 + - reproc 14.2.5.post0 hb9d3cd8_0 + license: MIT + license_family: MIT + purls: [] + size: 25665 + timestamp: 1731925852714 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/reproc-cpp-14.2.5.post0-h5ad3122_0.conda + sha256: 57831399b5c2ccc4a2ec4fad4ec70609ddc0e7098a1d8cca62e063860fd1674b + md5: fde98968589573ad478b504642319105 + depends: + - libgcc >=13 + - libstdcxx >=13 + - reproc 14.2.5.post0 h86ecc28_0 + license: MIT + license_family: MIT + purls: [] + size: 26291 + timestamp: 1745309832653 +- conda: https://conda.anaconda.org/conda-forge/osx-64/reproc-cpp-14.2.5.post0-h240833e_0.conda + sha256: 4d8638b7f44082302c7687c99079789f42068d34cddc0959c11ad5d28aab3d47 + md5: 420229341978751bd96faeced92c200e + depends: + - __osx >=10.13 + - libcxx >=18 + - reproc 14.2.5.post0 h6e16a3a_0 + license: MIT + license_family: MIT + purls: [] + size: 24394 + timestamp: 1731926392643 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/reproc-cpp-14.2.5.post0-h286801f_0.conda + sha256: f1b6aa9d9131ea159a5883bc5990b91b4b8f56eb52e0dc2b01aa9622e14edc81 + md5: 11a3d09937d250fc4423bf28837d9363 + depends: + - __osx >=11.0 + - libcxx >=18 + - reproc 14.2.5.post0 h5505292_0 + license: MIT + license_family: MIT + purls: [] + size: 24834 + timestamp: 1731926355120 +- conda: https://conda.anaconda.org/conda-forge/win-64/reproc-cpp-14.2.5.post0-he0c23c2_0.conda + sha256: ccf49fb5149298015ab410aae88e43600954206608089f0dfb7aea8b771bbe8e + md5: d2ce31fa746dddeb37f24f32da0969e9 + depends: + - reproc 14.2.5.post0 h2466b09_0 + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + license: MIT + license_family: MIT + purls: [] + size: 30096 + timestamp: 1731926177599 +- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda + sha256: 7813c38b79ae549504b2c57b3f33394cea4f2ad083f0994d2045c2e24cb538c5 + md5: c65df89a0b2e321045a9e01d1337b182 + depends: + - python >=3.10 + - certifi >=2017.4.17 + - charset-normalizer >=2,<4 + - idna >=2.5,<4 + - urllib3 >=1.21.1,<3 + - python + constrains: + - chardet >=3.0.2,<6 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/requests?source=compressed-mapping + size: 63602 + timestamp: 1766926974520 +- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.33.1-pyhcf101f3_0.conda + sha256: c0249bc4bf4c0e8e06d0e7b4d117a5d593cc4ab2144d5006d6d47c83cb0af18e + md5: 10afbb4dbf06ff959ad25a92ccee6e59 + depends: + - python >=3.10 + - certifi >=2023.5.7 + - charset-normalizer >=2,<4 + - idna >=2.5,<4 + - urllib3 >=1.26,<3 + - python + constrains: + - chardet >=3.0.2,<6 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/requests?source=compressed-mapping + size: 63712 + timestamp: 1774894783063 +- pypi: https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl + name: requests-toolbelt + version: 1.0.0 + sha256: cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06 + requires_dist: + - requests>=2.0.1,<3.0.0 + requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*' +- pypi: https://files.pythonhosted.org/packages/ff/9a/9afaade874b2fa6c752c36f1548f718b5b83af81ed9b76628329dab81c1b/rfc3986-2.0.0-py2.py3-none-any.whl + name: rfc3986 + version: 2.0.0 + sha256: 50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd + requires_dist: + - idna ; extra == 'idna2008' + requires_python: '>=3.7' +- conda: https://conda.anaconda.org/conda-forge/linux-64/rhash-1.4.6-hb9d3cd8_1.conda + sha256: d5c73079c1dd2c2a313c3bfd81c73dbd066b7eb08d213778c8bff520091ae894 + md5: c1c9b02933fdb2cfb791d936c20e887e + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 193775 + timestamp: 1748644872902 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/rhash-1.4.6-h86ecc28_1.conda + sha256: 0fe6f40213f2d8af4fcb7388eeb782a4e496c8bab32c189c3a34b37e8004e5a4 + md5: 745d02c0c22ea2f28fbda2cb5dbec189 + depends: + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 207475 + timestamp: 1748644952027 +- conda: https://conda.anaconda.org/conda-forge/osx-64/rhash-1.4.4-h0dc2134_0.conda + sha256: f1ae47e8c4e46f856faf5d8ee1e5291f55627aa93401b61a877f18ade5780c87 + md5: 55a2ada70c8a208c01f77978f2783121 + license: MIT + license_family: MIT + purls: [] + size: 177229 + timestamp: 1693456080514 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/rhash-1.4.4-hb547adb_0.conda + sha256: 3ab595e2280ed2118b6b1e8ce7e5949da2047846c81b6af1bbf5ac859d062edd + md5: 710c4b1abf65b697c1d9716eba16dbb0 + license: MIT + license_family: MIT + purls: [] + size: 177491 + timestamp: 1693456037505 +- pypi: https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl + name: rich + version: 14.3.3 + sha256: 793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d + requires_dist: + - ipywidgets>=7.5.1,<9 ; extra == 'jupyter' + - markdown-it-py>=2.2.0 + - pygments>=2.13.0,<3.0.0 + requires_python: '>=3.8.0' +- conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml-0.18.17-py310h139afa4_2.conda + sha256: 0741675606a288ca70a68282d9b8b67b61cc6e991dcec38bae9ec1e38237524c + md5: 26ad912afb7835e474284d61f482905d + depends: + - python + - ruamel.yaml.clib >=0.2.15 + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - python_abi 3.10.* *_cp310 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml?source=hash-mapping + size: 219162 + timestamp: 1766175793325 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml-0.18.17-py311haee01d2_2.conda + sha256: 5324d0353c9cca813501ea9b20186f8e6835cd4ff6e4dfa897c5faeecce8cdaa + md5: 672395a7f912a9eda492959b7632ae6c + depends: + - python + - ruamel.yaml.clib >=0.2.15 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - python_abi 3.11.* *_cp311 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml?source=hash-mapping + size: 294535 + timestamp: 1766175791754 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml-0.18.17-py314h0f05182_2.conda + sha256: 59f7773ed8c6f2bcab3e953e2b4816c86cf71e5508dc571f8073b8c2294b5787 + md5: 8ea76c64b49b16c37769ea7c4dca993b + depends: + - python + - ruamel.yaml.clib >=0.2.15 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml?source=hash-mapping + size: 308487 + timestamp: 1766175778417 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruamel.yaml-0.18.17-py310hef25091_2.conda + sha256: 4ba656144b8e56490f4dcec674310a4a7c411e43dfad8945c43c239c1faec898 + md5: e867ca69a8d4866b05a363bfddad2250 + depends: + - python + - ruamel.yaml.clib >=0.2.15 + - libgcc >=14 + - python 3.10.* *_cpython + - python_abi 3.10.* *_cp310 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml?source=hash-mapping + size: 222819 + timestamp: 1766175822103 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruamel.yaml-0.18.17-py311h51cfe5d_2.conda + sha256: b965d2023a41acbf76bd965e106835d19e6a26cd69c4e1d439df17471336226e + md5: ecf191a9fa6a518ca91aaa49e3c87584 + depends: + - python + - ruamel.yaml.clib >=0.2.15 + - libgcc >=14 + - python 3.11.* *_cpython + - python_abi 3.11.* *_cp311 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml?source=hash-mapping + size: 298156 + timestamp: 1766175797018 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruamel.yaml-0.18.17-py314h2e8dab5_2.conda + sha256: baedba4fb0d0929ffcbebd001876c115d23c5620457eb9347cdac5978963c262 + md5: 1f86e018331edc941dedc796c4373fe3 + depends: + - python + - ruamel.yaml.clib >=0.2.15 + - libgcc >=14 + - python 3.14.* *_cp314 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml?source=hash-mapping + size: 311783 + timestamp: 1766175823921 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml-0.17.40-py310hb372a2b_0.conda + sha256: a6f883e95ff6c0b48ecdc16113deae57961c24a3d9458ebabd489f61a9aae4d5 + md5: 150037c34bc1cd6bbe69876c4e7347f4 + depends: + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + - ruamel.yaml.clib >=0.1.2 + - setuptools + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml?source=hash-mapping + size: 200022 + timestamp: 1698138926099 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml-0.17.40-py311he705e18_0.conda + sha256: 0260c295cdfae417f107fe2fae66bae4eb260195885d81d8b1cd4fc6d81c849b + md5: 4796cc1d45c88ace8f5bb7950167a568 + depends: + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - ruamel.yaml.clib >=0.1.2 + - setuptools + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml?source=hash-mapping + size: 277064 + timestamp: 1698138918002 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml-0.18.17-py314hd330473_2.conda + sha256: 59edac475c2e53dda7802554aa8310b4214ef0a536841be4ab318e0b5b7563fc + md5: c64fb655de0ccaafb1d875f4fa1f0fc3 + depends: + - python + - ruamel.yaml.clib >=0.2.15 + - __osx >=10.13 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml?source=hash-mapping + size: 308947 + timestamp: 1766175829662 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruamel.yaml-0.17.40-py310hd125d64_0.conda + sha256: efc0814c8d5b9e20d75a425f0a9c782e5642a4a349849fa95c8b5b2f1108f6c9 + md5: 77e106fbe41acee97140e992dc52ad77 + depends: + - python >=3.10,<3.11.0a0 + - python >=3.10,<3.11.0a0 *_cpython + - python_abi 3.10.* *_cp310 + - ruamel.yaml.clib >=0.1.2 + - setuptools + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml?source=hash-mapping + size: 200368 + timestamp: 1698139000522 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruamel.yaml-0.17.40-py311h05b510d_0.conda + sha256: bf44774cbd03eb8d396a078b4af1b194f8600f8ca7ea7ca0e3d61dc16b400cb4 + md5: 640b6933c680860877b32a4c11076ab9 + depends: + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + - ruamel.yaml.clib >=0.1.2 + - setuptools + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml?source=hash-mapping + size: 276178 + timestamp: 1698139045095 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruamel.yaml-0.18.17-py314ha14b1ff_2.conda + sha256: 0f498e343be464219a99424260ff442144d0461a3a5eb30c9de6081af358b281 + md5: 87fc3a204f105e7e61c60a72509cccbd + depends: + - python + - ruamel.yaml.clib >=0.2.15 + - __osx >=11.0 + - python 3.14.* *_cp314 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml?source=hash-mapping + size: 311922 + timestamp: 1766175797575 +- conda: https://conda.anaconda.org/conda-forge/win-64/ruamel.yaml-0.18.17-py310h1637853_2.conda + sha256: cb42613022b37517a10064e399a9f5b929a02d6c8a135e84b248a69d39fc7a8a + md5: 20dfd23643ca21f251dfa6c6853c06c4 + depends: + - python + - ruamel.yaml.clib >=0.2.15 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - python_abi 3.10.* *_cp310 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml?source=hash-mapping + size: 217306 + timestamp: 1766175806668 +- conda: https://conda.anaconda.org/conda-forge/win-64/ruamel.yaml-0.18.17-py311hf893f09_2.conda + sha256: 90f4058642a6badfe710b2d1b0dd8cd802485303a209e6591c3c77ed74f0c363 + md5: a4d4fcbe5a1b6e5bae7cb5a1bac4919d + depends: + - python + - ruamel.yaml.clib >=0.2.15 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - python_abi 3.11.* *_cp311 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml?source=hash-mapping + size: 292781 + timestamp: 1766175809044 +- conda: https://conda.anaconda.org/conda-forge/win-64/ruamel.yaml-0.18.17-py314hc5dbbe4_2.conda + sha256: 62b73874b6c264a73e7904b33322128c4881c78dfe2fb9131becfbf84343ee2d + md5: 027ff6055e5c82ba4e085857f09302cb + depends: + - python + - ruamel.yaml.clib >=0.2.15 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml?source=hash-mapping + size: 306951 + timestamp: 1766175833786 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml.clib-0.2.15-py310h139afa4_1.conda + sha256: 242ff560883541acc447b4fb11f1c6c0a4e91479b70c8ce895aee5d9a8ce346a + md5: a7e3055859e9162d5f7adb9b3c229d56 + depends: + - python + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - python_abi 3.10.* *_cp310 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml-clib?source=hash-mapping + size: 152839 + timestamp: 1766159514181 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml.clib-0.2.15-py311haee01d2_1.conda + sha256: 2d7e8976b0542b7aae1a9e4383b7b1135e64e9e190ce394aed44983adc6eb3f2 + md5: e3dfd8043a0fac038fe0d7c2d08ac28c + depends: + - python + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - python_abi 3.11.* *_cp311 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml-clib?source=hash-mapping + size: 153044 + timestamp: 1766159530795 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml.clib-0.2.15-py314h0f05182_1.conda + sha256: 3bd8db7556e87c98933a47ff9f962af7b8e0dc3757a72180b27cbfcb1f98d2d9 + md5: 4f35ae1228a6c5d9df593367ffe8dda1 + depends: + - python + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml-clib?source=hash-mapping + size: 150041 + timestamp: 1766159514023 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruamel.yaml.clib-0.2.15-py310hef25091_1.conda + sha256: fc5cf2db69fab279d0be46a8a077d9354991be5f4d317a73c453fc8df7c69f0a + md5: e91e48a36a6c9f761e259b967878831a + depends: + - python + - python 3.10.* *_cpython + - libgcc >=14 + - python_abi 3.10.* *_cp310 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml-clib?source=hash-mapping + size: 153169 + timestamp: 1766159548278 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruamel.yaml.clib-0.2.15-py311h51cfe5d_1.conda + sha256: 77be521169904f2687cb09b6ab8d6bcee0d73d06284bfed84617668ad81c22f3 + md5: 471b202396dfeb16adde1930cd7a8001 + depends: + - python + - libgcc >=14 + - python 3.11.* *_cpython + - python_abi 3.11.* *_cp311 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml-clib?source=hash-mapping + size: 152961 + timestamp: 1766159559428 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ruamel.yaml.clib-0.2.15-py314h2e8dab5_1.conda + sha256: 18a34470b351fccfe6694215b01a9a68a0a9979336b0ea85709bbdeef0658e1c + md5: ca756356e2920f248a74cb42e0b4578d + depends: + - python + - python 3.14.* *_cp314 + - libgcc >=14 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml-clib?source=hash-mapping + size: 148495 + timestamp: 1766159541094 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml.clib-0.2.15-py314hd330473_1.conda + sha256: dbcc0ff6e902468314d10d9f59d289ad078e5eac02d72b9092fa96e88b91d5dd + md5: e41e8948899a09937c068f71fe65ebb6 + depends: + - python + - __osx >=10.13 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml-clib?source=hash-mapping + size: 136902 + timestamp: 1766159517466 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml.clib-0.2.8-py310hb372a2b_0.conda + sha256: 76535acf0bbefbbfeeca68bc732e4b8eea7526f0ef2090f2bdcf0283ec4b3738 + md5: a6254db88b5bf45d4870c3a63dc39e8d + depends: + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml-clib?source=hash-mapping + size: 118488 + timestamp: 1707314814452 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml.clib-0.2.8-py311he705e18_0.conda + sha256: e6d5b2c9a75191305c8d367d13218c0bd0cc7a640ae776b541124c0fe8341bc9 + md5: 3fdbde273667047893775e077cef290d + depends: + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml-clib?source=hash-mapping + size: 117859 + timestamp: 1707314957390 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruamel.yaml.clib-0.2.15-py314ha14b1ff_1.conda + sha256: ad575cae7f662b2dafca88c4ce05120e322f825c0610e54b0a116550c817bbbe + md5: 5836fbf79e5f279ffbe4ba06066c51a3 + depends: + - python + - python 3.14.* *_cp314 + - __osx >=11.0 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml-clib?source=hash-mapping + size: 133016 + timestamp: 1766159585543 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruamel.yaml.clib-0.2.8-py310hd125d64_0.conda + sha256: 83b27f5dafd201a9408886ff18af6ccdde45e748c934fce588a4b531cdd249d5 + md5: e0b9a24f19622386be17bf9f29674e81 + depends: + - python >=3.10,<3.11.0a0 + - python >=3.10,<3.11.0a0 *_cpython + - python_abi 3.10.* *_cp310 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml-clib?source=hash-mapping + size: 111512 + timestamp: 1707315215965 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruamel.yaml.clib-0.2.8-py311h05b510d_0.conda + sha256: 8b64d7ac6d544cdb1c5e3677c3a6ea10f1d87f818888b25df5f3b97f271ef14f + md5: 0fbb200e26cec1931d0337ee70422965 + depends: + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml-clib?source=hash-mapping + size: 111700 + timestamp: 1707315151942 +- conda: https://conda.anaconda.org/conda-forge/win-64/ruamel.yaml.clib-0.2.15-py310h1637853_1.conda + sha256: 3c2ba1f6757863affd1a2996cffcf63b2e13594300862cd38c9235b652a17ad7 + md5: 07f6b7231ccb637d76e1550ababded60 + depends: + - python + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - python_abi 3.10.* *_cp310 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml-clib?source=hash-mapping + size: 107521 + timestamp: 1766159541493 +- conda: https://conda.anaconda.org/conda-forge/win-64/ruamel.yaml.clib-0.2.15-py311hf893f09_1.conda + sha256: 5810ddd1efe4ac259ad0ff55778da71205a68edfbbb4d45488b270e7f2f23438 + md5: 4bf8909dc04f6ab8c6d7f2a2a4a51d19 + depends: + - python + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - python_abi 3.11.* *_cp311 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml-clib?source=hash-mapping + size: 107529 + timestamp: 1766159555820 +- conda: https://conda.anaconda.org/conda-forge/win-64/ruamel.yaml.clib-0.2.15-py314hc5dbbe4_1.conda + sha256: b719637ce71e533193cd2bcacbf6ba5c10deaafa1be90d96040ee2314c6b17d1 + md5: 496de351b0f9afe9e245229528304f25 + depends: + - python + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruamel-yaml-clib?source=hash-mapping + size: 105668 + timestamp: 1766159584330 +- conda: https://conda.anaconda.org/conda-forge/noarch/scikit-build-core-0.11.6-pyh7e86bf3_1.conda + sha256: bf802baa1a770c0ca631624a3627f84cae7978b56da02826b37ff1c5852a720a + md5: 4965b07e5cae94005cbe759e39f3def1 + depends: + - typing_extensions >=3.10.0 + - python >=3.8 + - exceptiongroup >=1.0 + - importlib-metadata >=4.13 + - importlib-resources >=1.3 + - packaging >=21.3 + - pathspec >=0.10.1 + - tomli >=1.2.2 + - typing-extensions >=3.10 + - python + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/scikit-build-core?source=hash-mapping + size: 213181 + timestamp: 1755919500167 +- pypi: https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl + name: secretstorage + version: 3.5.0 + sha256: 0ce65888c0725fcb2c5bc0fdb8e5438eece02c523557ea40ce0703c266248137 + requires_dist: + - cryptography>=2.0 + - jeepney>=0.6 + requires_python: '>=3.10' +- conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + sha256: 82088a6e4daa33329a30bc26dc19a98c7c1d3f05c0f73ce9845d4eab4924e9e1 + md5: 8e194e7b992f99a5015edbd4ebd38efd + depends: + - python >=3.10 + license: MIT + license_family: MIT + purls: + - pkg:pypi/setuptools?source=compressed-mapping + size: 639697 + timestamp: 1773074868565 +- conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-scm-9.2.2-pyhd8ed1ab_0.conda + sha256: 2161ac35fc22770b248bab0be2cc3b5bd765f528a9e60e7f3be784fd8d0d605a + md5: e2e4d7094d0580ccd62e2a41947444f3 + depends: + - importlib-metadata + - packaging >=20.0 + - python >=3.10 + - setuptools >=45 + - tomli >=1.0.0 + - typing-extensions + license: MIT + license_family: MIT + purls: + - pkg:pypi/setuptools-scm?source=hash-mapping + size: 52539 + timestamp: 1760965125925 +- conda: https://conda.anaconda.org/conda-forge/noarch/setuptools_scm-9.2.2-hd8ed1ab_0.conda + sha256: 60eec92bd931bbcba700b9a70b1446dccbf62d3298e408d3a28e09b8ecd96d98 + md5: 7537abc2590073ffde5545c648ad6974 + depends: + - setuptools-scm >=9.2.2,<9.2.3.0a0 + license: MIT + license_family: MIT + purls: [] + size: 6653 + timestamp: 1760965126461 +- conda: https://conda.anaconda.org/conda-forge/osx-64/sigtool-0.1.3-h88f4db0_0.tar.bz2 + sha256: 46fdeadf8f8d725819c4306838cdfd1099cd8fe3e17bd78862a5dfdcd6de61cf + md5: fbfb84b9de9a6939cb165c02c69b1865 + depends: + - openssl >=3.0.0,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 213817 + timestamp: 1643442169866 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/sigtool-0.1.3-h44b9a77_0.tar.bz2 + sha256: 70791ae00a3756830cb50451db55f63e2a42a2fa2a8f1bab1ebd36bbb7d55bff + md5: 4a2cac04f86a4540b8c9b8d8f597848f + depends: + - openssl >=3.0.0,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 210264 + timestamp: 1643442231687 +- conda: https://conda.anaconda.org/conda-forge/linux-64/simdjson-4.2.4-hb700be7_0.conda + sha256: ffe0c49e65486b485e66c7e116b1782189c970c16cb2fe9710a568e44bb9ede3 + md5: da6caa4c932708d447fb80eed702cb4e + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 294996 + timestamp: 1766034103379 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/simdjson-4.2.4-hfefdfc9_0.conda + sha256: 8731e7cb9438deb3275c4d33d402b99da12f250c4b0bd635a58784c5a01e38f5 + md5: 829b13867c30e5d44ab7d851bfdb5d63 + depends: + - libgcc >=14 + - libstdcxx >=14 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 260530 + timestamp: 1766034125791 +- conda: https://conda.anaconda.org/conda-forge/osx-64/simdjson-4.2.4-hcb651aa_0.conda + sha256: 33767091b867a05e47cdb8e756e84d82237be25a82f896ece073f06801ebfee7 + md5: 4670f8951ec3f5f3a09e7c580d964088 + depends: + - __osx >=10.13 + - libcxx >=19 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 286025 + timestamp: 1766034310103 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/simdjson-4.2.4-ha7d2532_0.conda + sha256: 142758c665c2a896c1f275213068b324e92f378b03ba8d0019f57d72ea319515 + md5: b6ac50035bdc00e3f01322c43062b855 + depends: + - __osx >=11.0 + - libcxx >=19 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 252462 + timestamp: 1766034371359 +- conda: https://conda.anaconda.org/conda-forge/win-64/simdjson-4.2.4-h49e36cd_0.conda + sha256: 4bb3d41240e455bffc919042d8bbe64ae6cfd560dc9eeda0e84fd8f33b53da26 + md5: c625e0530b27e3bad5f59fa00744bbb8 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 298171 + timestamp: 1766034112737 +- conda: https://conda.anaconda.org/conda-forge/linux-64/spdlog-1.17.0-hab81395_1.conda + sha256: c650f3df027afde77a5fbf58600ec4ed81a9edddf81f323cfb3e260f6dc19f56 + md5: a3b0e874fa56f72bc54e5c595712a333 + depends: + - __glibc >=2.17,<3.0.a0 + - fmt >=12.1.0,<12.2.0a0 + - libgcc >=14 + - libstdcxx >=14 + license: MIT + license_family: MIT + purls: [] + size: 196681 + timestamp: 1767781665629 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/spdlog-1.17.0-h9f97df7_1.conda + sha256: 36f5c0d73d88760438388bc940a65af4d9de3ecaf6fa5656a22a060d262d56f5 + md5: 910d3cbb4ccf371b6355a98b1233eb8f + depends: + - fmt >=12.1.0,<12.2.0a0 + - libgcc >=14 + - libstdcxx >=14 + license: MIT + license_family: MIT + purls: [] + size: 195699 + timestamp: 1767781668042 +- conda: https://conda.anaconda.org/conda-forge/osx-64/spdlog-1.17.0-h30f01e4_1.conda + sha256: a44fbcfdccf08211d39af11c08707b7f5748ad5e619adea7957decd21949018c + md5: 9ffcaf6ea8a92baea102b24c556140ae + depends: + - __osx >=10.13 + - fmt >=12.1.0,<12.2.0a0 + - libcxx >=19 + license: MIT + license_family: MIT + purls: [] + size: 173402 + timestamp: 1767782141460 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/spdlog-1.17.0-ha0f8610_1.conda + sha256: 465e81abc0e662937046a2c6318d1a9e74baee0addd51234d36e08bae6811296 + md5: 1885f7cface8cd627774407eeacb2caf + depends: + - __osx >=11.0 + - fmt >=12.1.0,<12.2.0a0 + - libcxx >=19 + license: MIT + license_family: MIT + purls: [] + size: 166603 + timestamp: 1767781942683 +- conda: https://conda.anaconda.org/conda-forge/win-64/spdlog-1.17.0-h9f585f1_1.conda + sha256: 90c9befa5f154463647c8e101bc7a4e05cb84b731e2dea5406bedfea02f8b012 + md5: 5c17c0a063b4d36b15d5f9c0ca5377a0 + depends: + - fmt >=12.1.0,<12.2.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: MIT + license_family: MIT + purls: [] + size: 174787 + timestamp: 1767781882230 +- conda: https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-64-2.28-h4ee821c_9.conda + sha256: c47299fe37aebb0fcf674b3be588e67e4afb86225be4b0d452c7eb75c086b851 + md5: 13dc3adbc692664cd3beabd216434749 + depends: + - __glibc >=2.28 + - kernel-headers_linux-64 4.18.0 he073ed8_9 + - tzdata + license: LGPL-2.0-or-later AND LGPL-2.0-or-later WITH exceptions AND GPL-2.0-or-later + license_family: GPL + purls: [] + size: 24008591 + timestamp: 1765578833462 +- conda: https://conda.anaconda.org/conda-forge/noarch/sysroot_linux-aarch64-2.28-h585391f_9.conda + sha256: 1bd2db6b2e451247bab103e4a0128cf6c7595dd72cb26d70f7fadd9edd1d1bc3 + md5: fdf07ab944a222ff28c754914fdb0740 + depends: + - __glibc >=2.28 + - kernel-headers_linux-aarch64 4.18.0 h05a177a_9 + - tzdata + license: LGPL-2.0-or-later AND LGPL-2.0-or-later WITH exceptions AND GPL-2.0-or-later + license_family: GPL + purls: [] + size: 23644746 + timestamp: 1765578629426 +- conda: https://conda.anaconda.org/conda-forge/osx-64/tapi-1100.0.11-h9ce4665_0.tar.bz2 + sha256: 34b18ce8d1518b67e333ca1d3af733c3976ecbdf3a36b727f9b4dedddcc588fa + md5: f9ff42ccf809a21ba6f8607f8de36108 + depends: + - libcxx >=10.0.0.a0 + license: NCSA + license_family: MIT + purls: [] + size: 201044 + timestamp: 1602664232074 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/tapi-1100.0.11-he4954df_0.tar.bz2 + sha256: 1709265fbee693a9e8b4126b0a3e68a6c4718b05821c659279c1af051f2d40f3 + md5: d83362e7d0513f35f454bc50b0ca591d + depends: + - libcxx >=11.0.0.a0 + license: NCSA + license_family: MIT + purls: [] + size: 191416 + timestamp: 1602687595316 +- conda: https://conda.anaconda.org/conda-forge/linux-64/taplo-0.10.0-h2d22210_1.conda + sha256: 7d313578d79ece2b328084d906958888b5a474326a24833317d95a71e264b219 + md5: a4935b2eea119342f6a9d666e821984d + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - openssl >=3.5.0,<4.0a0 + constrains: + - __glibc >=2.17 + license: MIT + license_family: MIT + purls: [] + size: 4319647 + timestamp: 1748302828104 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/taplo-0.10.0-h3618846_1.conda + sha256: 50944952f49509d1125bfafe2a958e55f5dc585dd6f7608c6707dd892e8356a8 + md5: 9bdb00138021e1f22b8d14a2f7fe52dc + depends: + - libgcc >=13 + - openssl >=3.5.0,<4.0a0 + constrains: + - __glibc >=2.17 + license: MIT + license_family: MIT + purls: [] + size: 4155701 + timestamp: 1748302870538 +- conda: https://conda.anaconda.org/conda-forge/osx-64/taplo-0.10.0-hffa81eb_1.conda + sha256: 47b343fd4779605c431f10e1bfe07e84df63884d4e081aafca027262b317bb7a + md5: c8ed0c445e126bc7519c32509b67fa2a + depends: + - __osx >=10.13 + - openssl >=3.5.0,<4.0a0 + constrains: + - __osx >=10.13 + license: MIT + license_family: MIT + purls: [] + size: 4286090 + timestamp: 1748302835791 +- conda: https://conda.anaconda.org/conda-forge/osx-64/taplo-0.8.1-h7205ca4_0.conda + sha256: 493b5f8db450f37e8bb50fdfd02c06499c18391c806d2220e65ac801f6b7c2f0 + md5: 8e99d4b2850401094fe7c83273d3c4e8 + license: MIT + license_family: MIT + purls: [] + size: 3446470 + timestamp: 1689048461323 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/taplo-0.10.0-h2b2570c_1.conda + sha256: c05b9d0bb740f48671d643d0e258639a3e727785b1eb62582385943ddabc5b6b + md5: 7b818d29210b93c231bc5bb0cd133d3b + depends: + - __osx >=11.0 + - openssl >=3.5.0,<4.0a0 + constrains: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 4005794 + timestamp: 1748302845549 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/taplo-0.8.1-h69fbcac_0.conda + sha256: 5a46bbdac42c2aa1d59f3f7f61aa92eaed5f6936b01de4f3519f5ad40374973f + md5: 268425eeb6db286378bb05f69331feea + license: MIT + license_family: MIT + purls: [] + size: 3339855 + timestamp: 1689048706766 +- conda: https://conda.anaconda.org/conda-forge/win-64/taplo-0.10.0-h63977a8_1.conda + sha256: b38dd1dd1fe52d26f739d144a85fd277103320bd8e037b66a299457d5a827a04 + md5: 5fc2fa2f444b00e0f5b1f60a23f2c2f8 + depends: + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + - ucrt >=10.0.20348.0 + license: MIT + license_family: MIT + purls: [] + size: 4441127 + timestamp: 1748302918824 +- conda: https://conda.anaconda.org/conda-forge/win-64/tbb-2022.3.0-h3155e25_2.conda + sha256: abd9a489f059fba85c8ffa1abdaa4d515d6de6a3325238b8e81203b913cf65a9 + md5: 0f9817ffbe25f9e69ceba5ea70c52606 + depends: + - libhwloc >=2.12.2,<2.12.3.0a0 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 155869 + timestamp: 1767886839029 +- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda + sha256: cafeec44494f842ffeca27e9c8b0c27ed714f93ac77ddadc6aaf726b5554ebac + md5: cffd3bdd58090148f4cfcd831f4b26ab + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libzlib >=1.3.1,<2.0a0 + constrains: + - xorg-libx11 >=1.8.12,<2.0a0 + license: TCL + license_family: BSD + purls: [] + size: 3301196 + timestamp: 1769460227866 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h0dc03b3_103.conda + sha256: e25c314b52764219f842b41aea2c98a059f06437392268f09b03561e4f6e5309 + md5: 7fc6affb9b01e567d2ef1d05b84aa6ed + depends: + - libgcc >=14 + - libzlib >=1.3.1,<2.0a0 + constrains: + - xorg-libx11 >=1.8.12,<2.0a0 + license: TCL + license_family: BSD + purls: [] + size: 3368666 + timestamp: 1769464148928 +- conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h1abcd95_1.conda + sha256: 30412b2e9de4ff82d8c2a7e5d06a15f4f4fef1809a72138b6ccb53a33b26faf5 + md5: bf830ba5afc507c6232d4ef0fb1a882d + depends: + - libzlib >=1.2.13,<2.0.0a0 + license: TCL + license_family: BSD + purls: [] + size: 3270220 + timestamp: 1699202389792 +- conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h7142dee_3.conda + sha256: 7f0d9c320288532873e2d8486c331ec6d87919c9028208d3f6ac91dc8f99a67b + md5: 6e6efb7463f8cef69dbcb4c2205bf60e + depends: + - __osx >=10.13 + - libzlib >=1.3.1,<2.0a0 + license: TCL + license_family: BSD + purls: [] + size: 3282953 + timestamp: 1769460532442 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda + sha256: 799cab4b6cde62f91f750149995d149bc9db525ec12595e8a1d91b9317f038b3 + md5: a9d86bc62f39b94c4661716624eb21b0 + depends: + - __osx >=11.0 + - libzlib >=1.3.1,<2.0a0 + license: TCL + license_family: BSD + purls: [] + size: 3127137 + timestamp: 1769460817696 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda + sha256: 72457ad031b4c048e5891f3f6cb27a53cb479db68a52d965f796910e71a403a8 + md5: b50a57ba89c32b62428b71a875291c9b + depends: + - libzlib >=1.2.13,<2.0.0a0 + license: TCL + license_family: BSD + purls: [] + size: 3145523 + timestamp: 1699202432999 +- conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h6ed50ae_3.conda + sha256: 0e79810fae28f3b69fe7391b0d43f5474d6bd91d451d5f2bde02f55ae481d5e3 + md5: 0481bfd9814bf525bd4b3ee4b51494c4 + depends: + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: TCL + license_family: BSD + purls: [] + size: 3526350 + timestamp: 1769460339384 +- conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.0-pyhcf101f3_0.conda + sha256: 62940c563de45790ba0f076b9f2085a842a65662268b02dd136a8e9b1eaf47a8 + md5: 72e780e9aa2d0a3295f59b1874e3768b + depends: + - python >=3.10 + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/tomli?source=compressed-mapping + size: 21453 + timestamp: 1768146676791 +- conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda + sha256: 9ef8e47cf00e4d6dcc114eb32a1504cc18206300572ef14d76634ba29dfe1eb6 + md5: e5ce43272193b38c2e9037446c1d9206 + depends: + - python >=3.10 + - __unix + - python + license: MPL-2.0 and MIT + purls: + - pkg:pypi/tqdm?source=compressed-mapping + size: 94132 + timestamp: 1770153424136 +- conda: https://conda.anaconda.org/conda-forge/noarch/tqdm-4.67.3-pyha7b4d00_0.conda + sha256: 63cc2def6e168622728c7800ed6b3c1761ceecb18b354c81cee1a0a94c09900a + md5: af77160f8428924c17db94e04aa69409 + depends: + - python >=3.10 + - colorama + - __win + - python + license: MPL-2.0 and MIT + purls: + - pkg:pypi/tqdm?source=hash-mapping + size: 93399 + timestamp: 1770153445242 +- conda: https://conda.anaconda.org/conda-forge/noarch/truststore-0.10.4-pyhcf101f3_0.conda + sha256: eece5be81588c39a855a0b70da84e0febb878a6d91dd27d6d21370ce9e5c5a46 + md5: c2db35b004913ec69bcac64fb0783de0 + depends: + - python >=3.10,<4 + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/truststore?source=hash-mapping + size: 24279 + timestamp: 1766494826559 +- pypi: https://files.pythonhosted.org/packages/3a/7a/882d99539b19b1490cac5d77c67338d126e4122c8276bf640e411650c830/twine-6.2.0-py3-none-any.whl + name: twine + version: 6.2.0 + sha256: 418ebf08ccda9a8caaebe414433b0ba5e25eb5e4a927667122fbe8f829f985d8 + requires_dist: + - readme-renderer>=35.0 + - requests>=2.20 + - requests-toolbelt>=0.8.0,!=0.9.0 + - urllib3>=1.26.0 + - importlib-metadata>=3.6 ; python_full_version < '3.10' + - keyring>=21.2.0 ; platform_machine != 'ppc64le' and platform_machine != 's390x' + - rfc3986>=1.4.0 + - rich>=12.0.0 + - packaging>=24.0 + - id + - keyring>=21.2.0 ; extra == 'keyring' + requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda + sha256: 7c2df5721c742c2a47b2c8f960e718c930031663ac1174da67c1ed5999f7938c + md5: edd329d7d3a4ab45dcf905899a7a6115 + depends: + - typing_extensions ==4.15.0 pyhcf101f3_0 + license: PSF-2.0 + license_family: PSF + purls: [] + size: 91383 + timestamp: 1756220668932 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + sha256: 032271135bca55aeb156cee361c81350c6f3fb203f57d024d7e5a1fc9ef18731 + md5: 0caa1af407ecff61170c9437a808404d + depends: + - python >=3.10 + - python + license: PSF-2.0 + license_family: PSF + purls: + - pkg:pypi/typing-extensions?source=hash-mapping + size: 51692 + timestamp: 1756220668932 +- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + sha256: 1d30098909076af33a35017eed6f2953af1c769e273a0626a04722ac4acaba3c + md5: ad659d0a2b3e47e38d829aa8cad2d610 + license: LicenseRef-Public-Domain + purls: [] + size: 119135 + timestamp: 1767016325805 +- conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda + sha256: 3005729dce6f3d3f5ec91dfc49fc75a0095f9cd23bab49efb899657297ac91a5 + md5: 71b24316859acd00bdb8b38f5e2ce328 + constrains: + - vc14_runtime >=14.29.30037 + - vs2015_runtime >=14.29.30037 + license: LicenseRef-MicrosoftWindowsSDK10 + purls: [] + size: 694692 + timestamp: 1756385147981 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.1.0-py310h03d9f68_0.conda + sha256: 24a1140fa1dcaf2d2b7da1014eba5801eae8c4c025bb17845a3b1b6c487cf8f7 + md5: c3b1f5bc28ae6282ba95156d18fde825 + depends: + - __glibc >=2.17,<3.0.a0 + - cffi + - libgcc >=14 + - libstdcxx >=14 + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ukkonen?source=hash-mapping + size: 14822 + timestamp: 1769438718477 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.1.0-py311hdf67eae_0.conda + sha256: 31ad759e2d7668f1615021bca0ae2358a284939e3ca3fcb971b3f7aa83c2a6d6 + md5: 5a715cf5e3dc6cd68717c50e47dd7b6b + depends: + - __glibc >=2.17,<3.0.a0 + - cffi + - libgcc >=14 + - libstdcxx >=14 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ukkonen?source=compressed-mapping + size: 14898 + timestamp: 1769438724694 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.1.0-py314h9891dd4_0.conda + sha256: c84034056dc938c853e4f61e72e5bd37e2ec91927a661fb9762f678cbea52d43 + md5: 5d3c008e54c7f49592fca9c32896a76f + depends: + - __glibc >=2.17,<3.0.a0 + - cffi + - libgcc >=14 + - libstdcxx >=14 + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ukkonen?source=hash-mapping + size: 15004 + timestamp: 1769438727085 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ukkonen-1.1.0-py310h0992a49_0.conda + sha256: 9547520cb3504f6acf364f4fa2447d19901360adae69701d7a3906458a7e3538 + md5: bac9c59669edb94e345b97412af6d283 + depends: + - cffi + - libgcc >=14 + - libstdcxx >=14 + - python >=3.10,<3.11.0a0 + - python >=3.10,<3.11.0a0 *_cpython + - python_abi 3.10.* *_cp310 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ukkonen?source=hash-mapping + size: 15584 + timestamp: 1769438771691 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ukkonen-1.1.0-py311hfca10b7_0.conda + sha256: 8870876bc36f47d7aea163843e01399c37153c7f448335f629d37f276bfa5010 + md5: 07e977e2a642a2348385860eb6fa84e9 + depends: + - cffi + - libgcc >=14 + - libstdcxx >=14 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ukkonen?source=hash-mapping + size: 15709 + timestamp: 1769438766154 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ukkonen-1.1.0-py314hd7d8586_0.conda + sha256: 0a7efe469d7e2a34a1d017bc51cf6fb9a51436730256983694c5ad74a33bd4e0 + md5: f3a967efabf9cf450b7741487318ea6e + depends: + - cffi + - libgcc >=14 + - libstdcxx >=14 + - python >=3.14,<3.15.0a0 + - python >=3.14,<3.15.0a0 *_cp314 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ukkonen?source=hash-mapping + size: 15756 + timestamp: 1769438772414 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ukkonen-1.0.1-py310h88cfcbd_4.conda + sha256: 662d357d36210e7cad2072e5e071b98fc18985ec36293f43139812efc29c6b4b + md5: 9b1aa3d9f02b72f2544ee531bb7ccea9 + depends: + - cffi + - libcxx >=15.0.7 + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ukkonen?source=hash-mapping + size: 13071 + timestamp: 1695549876888 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ukkonen-1.0.1-py311h5fe6e05_4.conda + sha256: b273782a1277042a54e12411beebd378d2a2a69e503bcf147766e98628e91c91 + md5: 8f750b84128d48dc8376572c5eace61e + depends: + - cffi + - libcxx >=15.0.7 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ukkonen?source=hash-mapping + size: 13193 + timestamp: 1695549883822 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ukkonen-1.1.0-py314h473ef84_0.conda + sha256: a77214fabb930c5332dece5407973c0c1c711298bf687976a0b6a9207b758e12 + md5: 08a26dd1ba8fc9681d6b5256b2895f8e + depends: + - __osx >=10.13 + - cffi + - libcxx >=19 + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ukkonen?source=hash-mapping + size: 14286 + timestamp: 1769439103231 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ukkonen-1.0.1-py310h38f39d4_4.conda + sha256: 3d668d21ba00d5e8c90c64cfaffc5bccd8b3349f584f1e96c7423f372289227a + md5: d44fc7ee5098e2cf4db125eda63878c6 + depends: + - cffi + - libcxx >=15.0.7 + - python >=3.10,<3.11.0a0 + - python >=3.10,<3.11.0a0 *_cpython + - python_abi 3.10.* *_cp310 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ukkonen?source=hash-mapping + size: 13807 + timestamp: 1695549789224 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ukkonen-1.0.1-py311he4fd1f5_4.conda + sha256: 384fc81a34e248019d43a115386f77859ab63e0e6f12dade486d76359703743f + md5: 5d5ab5c5af32931e03608034f4a5fd75 + depends: + - cffi + - libcxx >=15.0.7 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ukkonen?source=hash-mapping + size: 13958 + timestamp: 1695549884615 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ukkonen-1.1.0-py314h6cfcd04_0.conda + sha256: 033dbf9859fe58fb85350cf6395be6b1346792e1766d2d5acab538a6eb3659fb + md5: e229f444fbdb28d8c4f40e247154d993 + depends: + - __osx >=11.0 + - cffi + - libcxx >=19 + - python >=3.14,<3.15.0a0 + - python >=3.14,<3.15.0a0 *_cp314 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ukkonen?source=hash-mapping + size: 14884 + timestamp: 1769439056290 +- conda: https://conda.anaconda.org/conda-forge/win-64/ukkonen-1.1.0-py310he9f1925_0.conda + sha256: f66932dc9e68950dae39a6ccd5ef00503e433414e25267185ff8416cb3be1282 + md5: f63f6904311dc01152f624c828ee24b5 + depends: + - cffi + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ukkonen?source=hash-mapping + size: 18319 + timestamp: 1769438862573 +- conda: https://conda.anaconda.org/conda-forge/win-64/ukkonen-1.1.0-py311h3fd045d_0.conda + sha256: f30fdd8cdc5aa9800d6f05ed772d8e5b6427202c4bf2c86513ac62070215f19d + md5: fb1cf06b4259739eaa61d94bc219c0e8 + depends: + - cffi + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ukkonen?source=hash-mapping + size: 18452 + timestamp: 1769438859987 +- conda: https://conda.anaconda.org/conda-forge/win-64/ukkonen-1.1.0-py314h909e829_0.conda + sha256: 96990a5948e0c30788360836d94bf6145fdac0c187695ed9b3c2d61d9e11d267 + md5: 54e012b629ac5a40c9b3fa32738375dc + depends: + - cffi + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ukkonen?source=hash-mapping + size: 18504 + timestamp: 1769438844417 +- 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/urllib3-2.6.3-pyhd8ed1ab_0.conda + sha256: af641ca7ab0c64525a96fd9ad3081b0f5bcf5d1cbb091afb3f6ed5a9eee6111a + md5: 9272daa869e03efe68833e3dc7a02130 + depends: + - backports.zstd >=1.0.0 + - brotli-python >=1.2.0 + - h2 >=4,<5 + - pysocks >=1.5.6,<2.0,!=1.5.7 + - python >=3.10 + license: MIT + license_family: MIT + purls: + - pkg:pypi/urllib3?source=hash-mapping + size: 103172 + timestamp: 1767817860341 +- conda: https://conda.anaconda.org/conda-forge/win-64/vc-14.3-h41ae7f8_34.conda + sha256: 9dc40c2610a6e6727d635c62cced5ef30b7b30123f5ef67d6139e23d21744b3a + md5: 1e610f2416b6acdd231c5f573d754a0f + depends: + - vc14_runtime >=14.44.35208 + track_features: + - vc14 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 19356 + timestamp: 1767320221521 +- conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.44.35208-h818238b_34.conda + sha256: 02732f953292cce179de9b633e74928037fa3741eb5ef91c3f8bae4f761d32a5 + md5: 37eb311485d2d8b2c419449582046a42 + depends: + - ucrt >=10.0.20348.0 + - vcomp14 14.44.35208 h818238b_34 + constrains: + - vs2015_runtime 14.44.35208.* *_34 + license: LicenseRef-MicrosoftVisualCpp2015-2022Runtime + license_family: Proprietary + purls: [] + size: 683233 + timestamp: 1767320219644 +- conda: https://conda.anaconda.org/conda-forge/win-64/vcomp14-14.44.35208-h818238b_34.conda + sha256: 878d5d10318b119bd98ed3ed874bd467acbe21996e1d81597a1dbf8030ea0ce6 + md5: 242d9f25d2ae60c76b38a5e42858e51d + depends: + - ucrt >=10.0.20348.0 + constrains: + - vs2015_runtime 14.44.35208.* *_34 + license: LicenseRef-MicrosoftVisualCpp2015-2022Runtime + license_family: Proprietary + purls: [] + size: 115235 + timestamp: 1767320173250 +- conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda + sha256: b83246d145ba0e6814d2ed0b616293e56924e6c7d6649101f5a4f97f9e757ed1 + md5: 704c22301912f7e37d0a92b2e7d5942d + depends: + - python >=3.10 + - distlib >=0.3.7,<1 + - filelock <4,>=3.24.2 + - importlib-metadata >=6.6 + - platformdirs >=3.9.1,<5 + - python-discovery >=1 + - typing_extensions >=4.13.2 + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/virtualenv?source=compressed-mapping + size: 4647775 + timestamp: 1773133660203 +- conda: https://conda.anaconda.org/conda-forge/win-64/vs2022_win-64-19.44.35207-ha74f236_34.conda + sha256: 05bc657625b58159bcea039a35cc89d1f8baf54bf4060019c2b559a03ba4a45e + md5: 1d699ffd41c140b98e199ddd9787e1e1 + depends: + - vswhere + constrains: + - vs_win-64 2022.14 + track_features: + - vc14 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 23060 + timestamp: 1767320175868 +- conda: https://conda.anaconda.org/conda-forge/noarch/vswhere-3.1.7-h40126e0_1.conda + sha256: b72270395326dc56de9bd6ca82f63791b3c8c9e2b98e25242a9869a4ca821895 + md5: f622897afff347b715d046178ad745a5 + depends: + - __win + license: MIT + license_family: MIT + purls: [] + size: 238764 + timestamp: 1745560912727 +- conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_0.conda + sha256: d6cf2f0ebd5e09120c28ecba450556ce553752652d91795442f0e70f837126ae + md5: bdbd7385b4a67025ac2dba4ef8cb6a8f + depends: + - packaging >=24.0 + - python >=3.10 + license: MIT + license_family: MIT + purls: + - pkg:pypi/wheel?source=hash-mapping + size: 31858 + timestamp: 1769139207397 +- conda: https://conda.anaconda.org/conda-forge/noarch/win_inet_pton-1.1.0-pyh7428d3b_8.conda + sha256: 93807369ab91f230cf9e6e2a237eaa812492fe00face5b38068735858fba954f + md5: 46e441ba871f524e2b067929da3051c2 + depends: + - __win + - python >=3.9 + license: LicenseRef-Public-Domain + purls: + - pkg:pypi/win-inet-pton?source=hash-mapping + size: 9555 + timestamp: 1733130678956 +- conda: https://conda.anaconda.org/conda-forge/osx-64/xz-5.2.6-h775f41a_0.tar.bz2 + sha256: eb09823f34cc2dd663c0ec4ab13f246f45dcd52e5b8c47b9864361de5204a1c8 + md5: a72f9d4ea13d55d745ff1ed594747f10 + license: LGPL-2.1 and GPL-2.0 + purls: [] + size: 238119 + timestamp: 1660346964847 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 + sha256: 59d78af0c3e071021cfe82dc40134c19dab8cdf804324b62940f5c8cd71803ec + md5: 39c6b54e94014701dd157f4f576ed211 + license: LGPL-2.1 and GPL-2.0 + purls: [] + size: 235693 + timestamp: 1660346961024 +- conda: https://conda.anaconda.org/conda-forge/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/linux-aarch64/yaml-0.2.5-h80f16a2_3.conda + sha256: 66265e943f32ce02396ad214e27cb35f5b0490b3bd4f064446390f9d67fa5d88 + md5: 032d8030e4a24fe1f72c74423a46fb88 + depends: + - libgcc >=14 + license: MIT + license_family: MIT + purls: [] + size: 88088 + timestamp: 1753484092643 +- conda: https://conda.anaconda.org/conda-forge/osx-64/yaml-0.2.5-h0d85af4_2.tar.bz2 + sha256: 5301417e2c8dea45b401ffee8df3957d2447d4ce80c83c5ff151fc6bfe1c4148 + md5: d7e08fcf8259d742156188e8762b4d20 + license: MIT + license_family: MIT + purls: [] + size: 84237 + timestamp: 1641347062780 +- conda: https://conda.anaconda.org/conda-forge/osx-64/yaml-0.2.5-h4132b18_3.conda + sha256: a335161bfa57b64e6794c3c354e7d49449b28b8d8a7c4ed02bf04c3f009953f9 + md5: a645bb90997d3fc2aea0adf6517059bd + depends: + - __osx >=10.13 + license: MIT + license_family: MIT + purls: [] + size: 79419 + timestamp: 1753484072608 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h3422bc3_2.tar.bz2 + sha256: 93181a04ba8cfecfdfb162fc958436d868cc37db504c58078eab4c1a3e57fbb7 + md5: 4bb3f014845110883a3c5ee811fd84b4 + license: MIT + license_family: MIT + purls: [] + size: 88016 + timestamp: 1641347076660 +- 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/win-64/yaml-0.2.5-h6a83c73_3.conda + sha256: 80ee68c1e7683a35295232ea79bcc87279d31ffeda04a1665efdb43cbd50a309 + md5: 433699cba6602098ae8957a323da2664 + depends: + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + license: MIT + license_family: MIT + purls: [] + size: 63944 + timestamp: 1753484092156 +- conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-cpp-0.8.0-h3f2d84a_0.conda + sha256: 4b0b713a4308864a59d5f0b66ac61b7960151c8022511cdc914c0c0458375eca + md5: 92b90f5f7a322e74468bb4909c7354b5 + depends: + - libstdcxx >=13 + - libgcc >=13 + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 223526 + timestamp: 1745307989800 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-cpp-0.8.0-h5ad3122_0.conda + sha256: e146d83cdcf92506ab709c6e10acabd18a3394a23e6334a322c57e5d1d6d9f26 + md5: b9e5a9da5729019c4f216cf0d386a70c + depends: + - libstdcxx >=13 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 213281 + timestamp: 1745308220432 +- conda: https://conda.anaconda.org/conda-forge/osx-64/yaml-cpp-0.8.0-h92383a6_0.conda + sha256: 67d25c3aa2b4ee54abc53060188542d6086b377878ebf3e2b262ae7379e05a6d + md5: e15e9855092a8bdaaaed6ad5c173fffa + depends: + - libcxx >=18 + - __osx >=10.13 + license: MIT + license_family: MIT + purls: [] + size: 145204 + timestamp: 1745308032698 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-cpp-0.8.0-ha1acc90_0.conda + sha256: 66ba31cfb8014fdd3456f2b3b394df123bbd05d95b75328b7c4131639e299749 + md5: 30475b3d0406587cf90386a283bb3cd0 + depends: + - libcxx >=18 + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 136222 + timestamp: 1745308075886 +- conda: https://conda.anaconda.org/conda-forge/win-64/yaml-cpp-0.8.0-he0c23c2_0.conda + sha256: 031642d753e0ebd666a76cea399497cc7048ff363edf7d76a630ee0a19e341da + md5: 9bb5064a9fca5ca8e7d7f1ae677354b6 + depends: + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + - ucrt >=10.0.20348.0 + - vc >=14.2,<15 + - vc14_runtime >=14.29.30139 + - ucrt >=10.0.20348.0 + license: MIT + license_family: MIT + purls: [] + size: 148572 + timestamp: 1745308037198 +- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + sha256: b4533f7d9efc976511a73ef7d4a2473406d7f4c750884be8e8620b0ce70f4dae + md5: 30cd29cb87d819caead4d55184c1d115 + depends: + - python >=3.10 + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/zipp?source=hash-mapping + size: 24194 + timestamp: 1764460141901 +- conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py310h139afa4_1.conda + sha256: b0103e8bb639dbc6b9de8ef9a18a06b403b687a33dec83c25bd003190942259a + md5: 3741aefc198dfed2e3c9adc79d706bb7 + depends: + - python + - cffi >=1.11 + - zstd >=1.5.7,<1.5.8.0a0 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - zstd >=1.5.7,<1.6.0a0 + - python_abi 3.10.* *_cp310 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/zstandard?source=hash-mapping + size: 455614 + timestamp: 1762512676430 +- conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py311haee01d2_1.conda + sha256: d534a6518c2d8eccfa6579d75f665261484f0f2f7377b50402446a9433d46234 + md5: ca45bfd4871af957aaa5035593d5efd2 + depends: + - python + - cffi >=1.11 + - zstd >=1.5.7,<1.5.8.0a0 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - zstd >=1.5.7,<1.6.0a0 + - python_abi 3.11.* *_cp311 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/zstandard?source=hash-mapping + size: 466893 + timestamp: 1762512695614 +- conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py314h0f05182_1.conda + sha256: e589f694b44084f2e04928cabd5dda46f20544a512be2bdb0d067d498e4ac8d0 + md5: 2930a6e1c7b3bc5f66172e324a8f5fc3 + depends: + - python + - cffi >=1.11 + - zstd >=1.5.7,<1.5.8.0a0 + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - zstd >=1.5.7,<1.6.0a0 + - python_abi 3.14.* *_cp314 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/zstandard?source=hash-mapping + size: 473605 + timestamp: 1762512687493 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstandard-0.25.0-py310hef25091_1.conda + sha256: 30202c0e21618a421d189c70b71c152f53a6f605f8fb053a7faf844dffd4843b + md5: ef07dc8296f6e4df546b8d41bfb0a1fe + depends: + - python + - cffi >=1.11 + - zstd >=1.5.7,<1.5.8.0a0 + - python 3.10.* *_cpython + - libgcc >=14 + - zstd >=1.5.7,<1.6.0a0 + - python_abi 3.10.* *_cp310 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/zstandard?source=hash-mapping + size: 447338 + timestamp: 1762512738321 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstandard-0.25.0-py311h51cfe5d_1.conda + sha256: ddeec193065b235166fb9f8ca4e5cbb931215ab90cbd17e9f9d753c8966b57b1 + md5: c8b3365fe290eeee3084274948012394 + depends: + - python + - cffi >=1.11 + - zstd >=1.5.7,<1.5.8.0a0 + - python 3.11.* *_cpython + - libgcc >=14 + - zstd >=1.5.7,<1.6.0a0 + - python_abi 3.11.* *_cp311 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/zstandard?source=hash-mapping + size: 459426 + timestamp: 1762512724303 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstandard-0.25.0-py314h2e8dab5_1.conda + sha256: 051f12494f28f9de8b1bf1a787646c1f675d8eba0ba0eac79ab96ef960d24746 + md5: db33d0e8888bef6ef78207c5e6106a5b + depends: + - python + - cffi >=1.11 + - zstd >=1.5.7,<1.5.8.0a0 + - python 3.14.* *_cp314 + - libgcc >=14 + - python_abi 3.14.* *_cp314 + - zstd >=1.5.7,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/zstandard?source=hash-mapping + size: 465094 + timestamp: 1762512736835 +- conda: https://conda.anaconda.org/conda-forge/osx-64/zstandard-0.22.0-py310hd88f66e_0.conda + sha256: cdc8b9fc1352f19c73f16b0b0b3595a5a70758b3dfbd0398eac1db69910389bd + md5: 88c991558201cae2b7e690c2e9d2e618 + depends: + - cffi >=1.11 + - python >=3.10,<3.11.0a0 + - python_abi 3.10.* *_cp310 + - zstd >=1.5.5,<1.5.6.0a0 + - zstd >=1.5.5,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/zstandard?source=hash-mapping + size: 399250 + timestamp: 1698830565851 +- conda: https://conda.anaconda.org/conda-forge/osx-64/zstandard-0.22.0-py311hed14148_0.conda + sha256: 97e4ba1fb5a0d4310262da602bf283f058d63ab40e1dd74d93440f27823b1be5 + md5: 027bd8663474659bb949785d4e2b8599 + depends: + - cffi >=1.11 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - zstd >=1.5.5,<1.5.6.0a0 + - zstd >=1.5.5,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/zstandard?source=hash-mapping + size: 410219 + timestamp: 1698830417763 +- conda: https://conda.anaconda.org/conda-forge/osx-64/zstandard-0.25.0-py314hd1e8ddb_1.conda + sha256: cf12b4c138eef5160b12990278ac77dec5ca91de60638dd6cf1e60e4331d8087 + md5: b94712955dc017da312e6f6b4c6d4866 + depends: + - python + - cffi >=1.11 + - zstd >=1.5.7,<1.5.8.0a0 + - __osx >=10.13 + - python_abi 3.14.* *_cp314 + - zstd >=1.5.7,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/zstandard?source=hash-mapping + size: 470136 + timestamp: 1762512696464 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.22.0-py310h6289e41_0.conda + sha256: 806c1a7519dca20df58bce3b88392f2f4c2f04c0257789c2bd94b9c31b173dc2 + md5: f09fc5240964cceff0bbb2d68dbb6a5d + depends: + - cffi >=1.11 + - python >=3.10,<3.11.0a0 + - python >=3.10,<3.11.0a0 *_cpython + - python_abi 3.10.* *_cp310 + - zstd >=1.5.5,<1.5.6.0a0 + - zstd >=1.5.5,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/zstandard?source=hash-mapping + size: 320728 + timestamp: 1698830561905 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.22.0-py311h67b91a1_0.conda + sha256: 0bbe223fc0b6cb37f5f2287295f610e73a50888401c865448ce6db7bf79ac416 + md5: 396d81ee96c6d91c3bdfe13a785f4636 + depends: + - cffi >=1.11 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + - zstd >=1.5.5,<1.5.6.0a0 + - zstd >=1.5.5,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/zstandard?source=hash-mapping + size: 332059 + timestamp: 1698830508653 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.25.0-py314h9d33bd4_1.conda + sha256: cdeb350914094e15ec6310f4699fa81120700ca7ab7162a6b3421f9ea9c690b4 + md5: 8a92a736ab23b4633ac49dcbfcc81e14 + depends: + - python + - cffi >=1.11 + - zstd >=1.5.7,<1.5.8.0a0 + - python 3.14.* *_cp314 + - __osx >=11.0 + - python_abi 3.14.* *_cp314 + - zstd >=1.5.7,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/zstandard?source=hash-mapping + size: 397786 + timestamp: 1762512730914 +- conda: https://conda.anaconda.org/conda-forge/win-64/zstandard-0.25.0-py310h1637853_1.conda + sha256: db2a40dbe124b275fb0b8fdfd6e3b377963849897ab2b4d7696354040c52570b + md5: 1d261480977c268b3b209b7deaca0dd7 + depends: + - python + - cffi >=1.11 + - zstd >=1.5.7,<1.5.8.0a0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - python_abi 3.10.* *_cp310 + - zstd >=1.5.7,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/zstandard?source=hash-mapping + size: 364167 + timestamp: 1762512706699 +- conda: https://conda.anaconda.org/conda-forge/win-64/zstandard-0.25.0-py311hf893f09_1.conda + sha256: 10f089bedef1a28c663ef575fb9cec66b2058e342c4cf4a753083ab07591008f + md5: b2d90bca78b57c17205ce3ca1c427813 + depends: + - python + - cffi >=1.11 + - zstd >=1.5.7,<1.5.8.0a0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - python_abi 3.11.* *_cp311 + - zstd >=1.5.7,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/zstandard?source=hash-mapping + size: 375869 + timestamp: 1762512737575 +- conda: https://conda.anaconda.org/conda-forge/win-64/zstandard-0.25.0-py314hc5dbbe4_1.conda + sha256: 87bf6ba2dcc59dfbb8d977b9c29d19b6845ad54e092ea8204dcec62d7b461a30 + md5: c1ef46c3666be935fbb7460c24950cff + depends: + - python + - cffi >=1.11 + - zstd >=1.5.7,<1.5.8.0a0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - zstd >=1.5.7,<1.6.0a0 + - python_abi 3.14.* *_cp314 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/zstandard?source=hash-mapping + size: 381179 + timestamp: 1762512709971 +- conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + sha256: 68f0206ca6e98fea941e5717cec780ed2873ffabc0e1ed34428c061e2c6268c7 + md5: 4a13eeac0b5c8e5b8ab496e6c4ddd829 + depends: + - __glibc >=2.17,<3.0.a0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 601375 + timestamp: 1764777111296 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda + sha256: 569990cf12e46f9df540275146da567d9c618c1e9c7a0bc9d9cfefadaed20b75 + md5: c3655f82dcea2aa179b291e7099c1fcc + depends: + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 614429 + timestamp: 1764777145593 +- conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.5-h829000d_0.conda + sha256: d54e31d3d8de5e254c0804abd984807b8ae5cd3708d758a8bf1adff1f5df166c + md5: 80abc41d0c48b82fe0f04e7f42f5cb7e + depends: + - libzlib >=1.2.13,<2.0.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 499383 + timestamp: 1693151312586 +- conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-h3eecb57_6.conda + sha256: 47101a4055a70a4876ffc87b750ab2287b67eca793f21c8224be5e1ee6394d3f + md5: 727109b184d680772e3122f40136d5ca + depends: + - __osx >=10.13 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 528148 + timestamp: 1764777156963 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.5-h4f39d0f_0.conda + sha256: 7e1fe6057628bbb56849a6741455bbb88705bae6d6646257e57904ac5ee5a481 + md5: 5b212cfb7f9d71d603ad891879dc7933 + depends: + - libzlib >=1.2.13,<2.0.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 400508 + timestamp: 1693151393180 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda + sha256: 9485ba49e8f47d2b597dd399e88f4802e100851b27c21d7525625b0b4025a5d9 + md5: ab136e4c34e97f34fb621d2592a393d8 + depends: + - __osx >=11.0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 433413 + timestamp: 1764777166076 +- conda: https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.7-h534d264_6.conda + sha256: 368d8628424966fd8f9c8018326a9c779e06913dd39e646cf331226acc90e5b2 + md5: 053b84beec00b71ea8ff7a4f84b55207 + depends: + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 388453 + timestamp: 1764777142545 diff --git a/pixi.toml b/pixi.toml new file mode 100644 index 00000000..5f89234d --- /dev/null +++ b/pixi.toml @@ -0,0 +1,211 @@ +[workspace] +authors = [ + "Insight Software Consortium <>", + "Matt McCormick ", + "Jean-Christophe Fillion-Robin ", + "Tom Birdsong ", + "Hans J. Johnson ", + "Dženan Zukić ", + "Simon Rit ", + "Francois Budin ", + "LucasGandel ", + "Davis Marc Vigneault ", + "Jon Haitz Legarreta Gorroño ", + "Lee Newberg ", + "Cavan Riley ", +] + +name = "ITKPythonPackage" +version = "0.1.0" +channels = ["conda-forge"] +platforms = ["linux-64", "linux-aarch64", "osx-64", "osx-arm64", "win-64"] + +######################################## +# Common features used by all envs +######################################## + +# Build tooling shared by all platforms +[feature.build-dev-tools] +[feature.build-dev-tools.dependencies] +cmake = ">=3.26,<4" +doxygen = "<2" +ninja = ">=1.11.1,<2" +pkginfo = ">=1.12.1.2,<2" + +# Python packaging/build support shared by all platforms +[feature.python-dev-pkgs] +[feature.python-dev-pkgs.dependencies] +numpy = ">=1.26" +packaging = ">=25.0,<26" +pathspec = "*" +pyproject-metadata = "*" +scikit-build-core = ">=0.11.6,<0.12.0" +setuptools_scm = ">=9.2.0" +setuptools = ">=61" +tomli = "*" +pip = "*" + +[feature.python-dev-pkgs.pypi-dependencies] +build = "*" + +######################################## +# Manylinux-specific features +######################################## + +# Shared dependencies for all manylinux wheel builds +# (might be helpful for including newer manylinux versions later) +[feature.manylinux-common-build] +platforms = ["linux-64", "linux-aarch64"] + +[feature.manylinux-common-build.dependencies] +auditwheel = "*" +patchelf = "*" # Needed for auditwheel +wheel = "*" + +[feature.manylinux-common-build.pypi-dependencies] +build = "*" + +[feature.linux-build] +platforms = ["linux-64", "linux-aarch64"] + +[feature.linux-build.dependencies] +cxx-compiler = "==1.11.0" +c-compiler = "==1.11.0" +libhwloc = "*" # Needed for tbb +auditwheel = "*" +patchelf = "*" # Needed for auditwheel +wheel = "*" + +[feature.manylinux228-build] +platforms = ["linux-64", "linux-aarch64"] + +[feature.manylinux228-build.system-requirements] +linux = "5.4" +libc = { family = "glibc", version = "2.28" } + +[feature.linux-build.activation.env] +PYTHONNOUSERSITE = "1" # Exclude system .local site packages + +######################################## +# macOS-specific feature +######################################## + +[feature.macosx-build] +platforms = ["osx-64", "osx-arm64"] +system-requirements = { macos = "10.7" } + +# delocate is a Python tool; cxx-compiler is the macOS toolchain meta-package +[feature.macosx-build.pypi-dependencies] +delocate = "*" + +[feature.macosx-build.dependencies] +cxx-compiler = "==1.10.0" # XCode 16.0 before castxml required updates +c-compiler = "==1.10.0" # XCode 16.0 before castxml required updates +#libhwloc = "*" # Needed for tbb + +[feature.windows-build] +platforms = ["win-64"] + +[feature.windows-build.dependencies] +git = "*" # Git is not always available in PowerShell by default +cxx-compiler = "==1.11.0" # MSVC 2022 +c-compiler = "==1.11.0" # MSVC 2022 + +[feature.windows-build.pypi-dependencies] +delvewheel = "*" +# windows = "*" + +[feature.py310] +[feature.py310.dependencies] +python = ">=3.10,<3.11" + +[feature.py311] +[feature.py311.dependencies] +python = ">=3.11,<3.12" + +#[feature.py312] +#[feature.py312.dependencies] +#python = ">=3.12,<3.13" +# +#[feature.py313] +#[feature.py313.dependencies] +#python = ">=3.13,<3.14" +# +#[feature.py314] +#[feature.py314.dependencies] +#python = ">=3.14,<3.15" + +######################################## +# Publishing feature (no compilers needed) +######################################## +[feature.publish] +[feature.publish.dependencies] +python = ">=3.10" +gh = "*" +zstd = "*" + +[feature.publish.pypi-dependencies] +twine = ">=6.0" + + +######################################## +# Environments: compose features per target +######################################## + +[environments] +publish = ["publish"] +linux-py310 = ["py310", "linux-build", "build-dev-tools", "python-dev-pkgs"] +linux-py311 = ["py311", "linux-build", "build-dev-tools", "python-dev-pkgs"] + +# Manylinux wheel-build env (docker manylinux228 images, CI, etc.) +manylinux228-py310 = [ + "py310", + "manylinux-common-build", + "manylinux228-build", + "build-dev-tools", + "python-dev-pkgs", +] +manylinux228-py311 = [ + "py311", + "manylinux-common-build", + "manylinux228-build", + "build-dev-tools", + "python-dev-pkgs", +] + + +# macOS build env (both Intel and Apple Silicon) +macosx-py310 = ["py310", "build-dev-tools", "python-dev-pkgs", "macosx-build"] +macosx-py311 = ["py311", "build-dev-tools", "python-dev-pkgs", "macosx-build"] + +# Windows build env +windows-py310 = ["py310", "build-dev-tools", "python-dev-pkgs", "windows-build"] +windows-py311 = ["py311", "build-dev-tools", "python-dev-pkgs", "windows-build"] + +[dependencies] +# pixi-pycharm and conda are only needed to support development in pycharm +# https://pixi.prefix.dev/v0.21.1/ide_integration/pycharm/#how-to-use +pixi-pycharm = ">=0.0.10,<0.0.11" +conda = "*" +taplo = ">=0.8.1,<0.11" +pre-commit = "*" + +[tasks] +taplo = "fmt pixi.toml" + +[tasks.build-itk-wheels] +cmd = ["python", "scripts/build_wheels.py"] + +[tasks.pre-commit-install] +cmd = "pre-commit install -f -t pre-commit -t prepare-commit-msg -t commit-msg --hook-type commit-msg --install-hooks" + +[tasks.pre-commit-run] +cmd = "pre-commit run --all-files" + +[tasks.publish-wheels] +cmd = ["python", "scripts/publish_wheels.py"] +description = "Upload built wheels to PyPI (or TestPyPI with --test)" + +[tasks.publish-tarball-cache] +cmd = ["python", "scripts/publish_tarball_cache.py"] +description = "Upload .tar.zst/.zip build caches to GitHub Releases" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..5871eda1 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,65 @@ +# Root-level pyproject.toml — developer tooling configuration only. +# This file configures linters/formatters for the ITKPythonPackage build scripts. +# It does NOT define a Python package; wheel-specific pyproject.toml files are +# generated dynamically by scripts/pyproject_configure.py into build subdirectories. + +[tool.black] +line-length = 88 +target-version = ["py310", "py311"] + +[tool.ruff] +line-length = 88 +target-version = "py310" + +[tool.ruff.lint] +# E/F: pycodestyle errors + pyflakes +# I: isort import ordering +# UP: pyupgrade (modernise syntax for Python 3.10+) +# B: flake8-bugbear (opinionated bug detection) +select = ["E", "F", "I", "UP", "B"] +# E501 (line-too-long) is handled by black; suppress here to avoid duplication +ignore = ["E501"] + +[tool.commitizen] +name = "cz_customize" + +[tool.commitizen.customize] +message_template = "{{change_type}}: {{message}}" +example = "ENH: Add support for Python 3.12" +schema = ": " +schema_pattern = "(BUG|COMP|DOC|ENH|PERF|STYLE): [A-Z].*" +bump_pattern = "^(ENH|BUG|COMP|PERF)" +bump_map = { "ENH" = "MINOR", "BUG" = "PATCH", "COMP" = "PATCH", "PERF" = "PATCH" } +commit_parser = "^(?PBUG|COMP|DOC|ENH|PERF|STYLE): (?P.*)" +changelog_pattern = "^(BUG|COMP|DOC|ENH|PERF|STYLE)?(!)?" +change_type_map = { "ENH" = "Enhancements", "BUG" = "Bug Fixes", "COMP" = "Build Fixes", "DOC" = "Documentation", "PERF" = "Performance", "STYLE" = "Style" } +change_type_order = ["Enhancements", "Bug Fixes", "Build Fixes", "Performance", "Documentation", "Style"] +info = """ +ITK commit message convention: PREFIX: Description + +Valid prefixes: + BUG: a bug fix + COMP: a compilation/build fix + DOC: documentation changes + ENH: new feature or enhancement + PERF: performance improvement + STYLE: code style/formatting (no logic change) +""" + +[[tool.commitizen.customize.questions]] +type = "list" +name = "change_type" +message = "Select the type of change:" +choices = [ + { value = "ENH", name = "ENH: A new feature or enhancement", key = "e" }, + { value = "BUG", name = "BUG: A bug fix", key = "b" }, + { value = "COMP", name = "COMP: A compilation/build fix", key = "c" }, + { value = "DOC", name = "DOC: Documentation changes", key = "d" }, + { value = "PERF", name = "PERF: A performance improvement", key = "p" }, + { value = "STYLE", name = "STYLE: Code style/formatting (no logic change)", key = "s" }, +] + +[[tool.commitizen.customize.questions]] +type = "input" +name = "message" +message = "Commit description (start with capital letter):" diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index 5fac7875..00000000 --- a/requirements-dev.txt +++ /dev/null @@ -1,6 +0,0 @@ -ninja==1.11.1.1 -scikit-build-core==0.10.7 -build==1.2.1 -pyproject-metadata -pathspec -setuptools_scm==8.1.0 diff --git a/scripts/BuildManager.py b/scripts/BuildManager.py new file mode 100644 index 00000000..a7fd9942 --- /dev/null +++ b/scripts/BuildManager.py @@ -0,0 +1,134 @@ +import json +import time +from datetime import datetime +from pathlib import Path + + +class BuildManager: + """Manage a JSON build report for multistep runs. + + Persists status and timing for each named step to a JSON file. + Steps already marked ``"done"`` are skipped on subsequent runs, + enabling resumable builds. + + Parameters + ---------- + report_path : Path + Path to the JSON report file (created if absent). + step_names : list[str] + Ordered names of build steps to track. + + Attributes + ---------- + report : dict + In-memory report structure with ``created_at``, ``updated_at``, + and ``steps`` keys. + """ + + def __init__(self, report_path: Path, step_names: list[str]): + self.report_path = Path(report_path) + self._init_structure(step_names) + self._load_if_exists() + + # ---- Public API ---- + def run_step(self, step_name: str, func, force_rerun=False) -> None: + """Execute a build step, recording timing and status. + + Parameters + ---------- + step_name : str + Key identifying the step in the report. + func : callable + Zero-argument callable that performs the step's work. + force_rerun : bool, optional + If True, re-execute even when the step is already ``"done"``. + + Raises + ------ + Exception + Re-raises any exception thrown by *func* after recording + the failure in the report. + """ + entry = self.report["steps"].setdefault(step_name, self._new_step_entry()) + if entry.get("status") == "done" and not force_rerun: + # Already completed in a previous run; skip + return + + # Mark start + entry["status"] = "running" + entry["started_at"] = self._now() + self.report["updated_at"] = entry["started_at"] + self.save() + + start = time.perf_counter() + try: + func() + except Exception as e: + # Record failure and re-raise + entry["status"] = "failed" + entry["finished_at"] = self._now() + entry["duration_sec"] = round(time.perf_counter() - start, 3) + entry["error"] = f"{type(e).__name__}: {e}" + self.report["updated_at"] = entry["finished_at"] + self.save() + raise + else: + # Record success + entry["status"] = "done" + entry["finished_at"] = self._now() + entry["duration_sec"] = round(time.perf_counter() - start, 3) + self.report["updated_at"] = entry["finished_at"] + self.save() + + def save(self) -> None: + """Write the current report to disk atomically.""" + self.report_path.parent.mkdir(parents=True, exist_ok=True) + tmp = self.report_path.with_suffix(self.report_path.suffix + ".tmp") + with open(tmp, "w", encoding="utf-8") as f: + json.dump(self.report, f, indent=2, sort_keys=True) + tmp.replace(self.report_path) + + # ---- Internal helpers ---- + def _init_structure(self, step_names: list[str]) -> None: + steps = {name: self._new_step_entry() for name in step_names} + now = self._now() + self.report = { + "created_at": now, + "updated_at": now, + "steps": steps, + } + + def _load_if_exists(self) -> None: + if not self.report_path.exists(): + return + try: + with open(self.report_path, encoding="utf-8") as f: + existing = json.load(f) + # Merge existing with current set of steps, preserving statuses + existing_steps = existing.get("steps", {}) + for name in self.report["steps"].keys(): + if name in existing_steps: + self.report["steps"][name] = existing_steps[name] + # Bring over timestamps + self.report["created_at"] = existing.get( + "created_at", self.report["created_at"] + ) + self.report["updated_at"] = existing.get( + "updated_at", self.report["updated_at"] + ) + except Exception as e: + # Corrupt or unreadable file; keep freshly initialized structure + raise RuntimeError(f"Failed to load build report: {e}") from e + + @staticmethod + def _now() -> str: + return datetime.now().isoformat(timespec="seconds") + + @staticmethod + def _new_step_entry() -> dict: + return { + "status": "pending", + "started_at": None, + "finished_at": None, + "duration_sec": None, + } diff --git a/scripts/build_python_instance_base.py b/scripts/build_python_instance_base.py new file mode 100644 index 00000000..fd5d3763 --- /dev/null +++ b/scripts/build_python_instance_base.py @@ -0,0 +1,1467 @@ +import copy +import os +import shutil +import subprocess +import sys +from abc import ABC, abstractmethod +from collections import OrderedDict +from collections.abc import Callable +from os import environ +from pathlib import Path + +from BuildManager import BuildManager +from cmake_argument_builder import CMakeArgumentBuilder +from pyproject_configure import configure_one_pyproject_file +from wheel_builder_utils import ( + _remove_tree, + _which, + get_default_platform_build, + run_commandLine_subprocess, +) + + +class BuildPythonInstanceBase(ABC): + """Abstract base class to build wheels for a single Python environment. + + Concrete subclasses implement platform-specific details (environment + setup, wheel fixup, tarball creation) while this class provides the + shared build orchestration, CMake configuration, and wheel-building + logic. + + Parameters + ---------- + platform_env : str + Platform/environment identifier (e.g. ``'manylinux228-py311'``). + build_dir_root : Path + Root directory for all build artifacts. + package_env_config : dict + Mutable configuration dictionary populated throughout the build. + cleanup : bool + Whether to remove intermediate build artifacts. + build_itk_tarball_cache : bool + Whether to create a reusable tarball of the ITK build tree. + cmake_options : list[str] + Extra ``-D`` options forwarded to CMake. + windows_extra_lib_paths : list[str] + Additional library paths for Windows wheel fixup (delvewheel). + dist_dir : Path + Output directory for built wheel files. + module_source_dir : Path, optional + Path to an external ITK remote module to build. + module_dependencies_root_dir : Path, optional + Directory where remote module dependencies are cloned. + itk_module_deps : str, optional + Colon-delimited dependency specifications for remote modules. + skip_itk_build : bool, optional + Skip the ITK C++ build step. + skip_itk_wheel_build : bool, optional + Skip the ITK wheel build step. + """ + + def __init__( + self, + *, + platform_env, + build_dir_root, + package_env_config: dict, + cleanup: bool, + build_itk_tarball_cache: bool, + cmake_options: list[str], + windows_extra_lib_paths: list[str], + dist_dir: Path, + module_source_dir: Path | None = None, + module_dependencies_root_dir: Path | None = None, + itk_module_deps: str | None = None, + skip_itk_build: bool | None = None, + skip_itk_wheel_build: bool | None = None, + ) -> None: + self.build_node_cpu_count: int = os.cpu_count() or 1 + self.platform_env = platform_env + self.ipp_dir = Path(__file__).parent.parent + + self.build_dir_root = build_dir_root + self.cmake_itk_source_build_configurations: CMakeArgumentBuilder = ( + CMakeArgumentBuilder() + ) + self.cmake_compiler_configurations: CMakeArgumentBuilder = ( + CMakeArgumentBuilder() + ) + # TODO: Partial refactoring cleanup later + package_env_config["IPP_SOURCE_DIR"] = self.ipp_dir + IPP_BuildWheelsSupport_DIR: Path = self.ipp_dir / "BuildWheelsSupport" + package_env_config["IPP_BuildWheelsSupport_DIR"] = IPP_BuildWheelsSupport_DIR + + self.package_env_config = package_env_config + + # declare this dict before self.prepare_build_env() or dict will be empty in later functions + self.venv_info_dict = { + # Filled in for each platform and each pyenvs + # "python_executable": None, + # "python_include_dir": None, + # "python_library": None, + # "venv_bin_path": None, + # "venv_base_dir": None, + } + + with open( + IPP_BuildWheelsSupport_DIR / "WHEEL_NAMES.txt", + encoding="utf-8", + ) as content: + self.wheel_names = [ + wheel_name.strip() for wheel_name in content.readlines() + ] + del package_env_config + + self.cleanup = cleanup + self.build_itk_tarball_cache = build_itk_tarball_cache + self.cmake_options = cmake_options + self.windows_extra_lib_paths = windows_extra_lib_paths + self.dist_dir = dist_dir + # Needed for processing remote modules and their dependencies + self.module_source_dir: Path = ( + Path(module_source_dir) if module_source_dir else None + ) + self.module_dependencies_root_dir: Path = ( + Path(module_dependencies_root_dir) if module_dependencies_root_dir else None + ) + self.itk_module_deps = itk_module_deps + self.skip_itk_build = skip_itk_build + self.skip_itk_wheel_build = skip_itk_wheel_build + self.prepare_build_env() + + self.package_env_config["BUILD_TYPE"] = "Release" + # Unified place to collect cmake -D definitions for this instance + self.cmake_cmdline_definitions: CMakeArgumentBuilder = CMakeArgumentBuilder() + # Seed from legacy cmake_options if provided as ['-D=', ...] + if cmake_options: + for opt in cmake_options: + if not opt.startswith("-D"): + continue + # Strip leading -D, split on first '=' into key and value + try: + key, value = opt[2:].split("=", 1) + except ValueError: + # Malformed option; skip to avoid breaking build + continue + # Preserve value verbatim (may contain quotes) + self.cmake_cmdline_definitions.set(key, value) + + self.cmake_compiler_configurations.update( + { + "CMAKE_BUILD_TYPE:STRING": self.package_env_config["BUILD_TYPE"], + } + ) + # Set cmake flags for the compiler if CC or CXX are specified + cxx_compiler: str = self.package_env_config.get("CXX", "") + if cxx_compiler != "": + self.cmake_compiler_configurations.set( + "CMAKE_CXX_COMPILER:STRING", cxx_compiler + ) + + c_compiler: str = self.package_env_config.get("CC", "") + if c_compiler != "": + self.cmake_compiler_configurations.set( + "CMAKE_C_COMPILER:STRING", c_compiler + ) + + if self.package_env_config.get("USE_CCACHE", "OFF") == "ON": + ccache_exe: Path = _which("ccache") + self.cmake_compiler_configurations.set( + "CMAKE_C_COMPILER_LAUNCHER:FILEPATH", f"{ccache_exe}" + ) + self.cmake_compiler_configurations.set( + "CMAKE_CXX_COMPILER_LAUNCHER:FILEPATH", f"{ccache_exe}" + ) + + self.cmake_itk_source_build_configurations.update( + # ITK wrapping options + { + "ITK_SOURCE_DIR:PATH": f"{self.package_env_config['ITK_SOURCE_DIR']}", + "BUILD_TESTING:BOOL": "OFF", + "ITK_WRAP_unsigned_short:BOOL": "ON", + "ITK_WRAP_double:BOOL": "ON", + "ITK_WRAP_complex_double:BOOL": "ON", + "ITK_WRAP_IMAGE_DIMS:STRING": "2;3;4", + "WRAP_ITK_INSTALL_COMPONENT_IDENTIFIER:STRING": "PythonWheel", + "WRAP_ITK_INSTALL_COMPONENT_PER_MODULE:BOOL": "ON", + "PY_SITE_PACKAGES_PATH:PATH": ".", + "ITK_LEGACY_SILENT:BOOL": "ON", + "ITK_WRAP_PYTHON:BOOL": "ON", + "ITK_WRAP_DOC:BOOL": "ON", + "DOXYGEN_EXECUTABLE:FILEPATH": f"{self.package_env_config['DOXYGEN_EXECUTABLE']}", + "Module_ITKTBB:BOOL": self.package_env_config["USE_TBB"], + "TBB_DIR:PATH": self.package_env_config["TBB_DIR"], + # Python settings + "SKBUILD:BOOL": "ON", + } + ) + + def update_venv_itk_build_configurations(self) -> None: + """Set ``Python3_ROOT_DIR`` in ITK build configurations from venv info.""" + # Python3_EXECUTABLE, Python3_INCLUDE_DIR, and Python3_LIBRARY are validated + # and resolved by find_package(Python3) in cmake/ITKPythonPackage_SuperBuild.cmake + # when not already defined. Python3_ROOT_DIR is set here to guide that search. + self.cmake_itk_source_build_configurations.set( + "Python3_ROOT_DIR:PATH", f"{self.venv_info_dict['python_root_dir']}" + ) + + def _detect_conda_itk(self) -> Path | None: + """Detect a pre-installed ITK from a conda/pixi environment. + + Checks ``CONDA_PREFIX`` (or ``PIXI_ENVIRONMENT_DIR``) for an + installed ITK CMake config directory. When found, the superbuild + and C++ build steps can be skipped entirely. + + Returns + ------- + Path or None + Path to the ITK CMake config directory, or *None* if not found. + """ + for env_var in ("CONDA_PREFIX", "PIXI_ENVIRONMENT_DIR"): + prefix = os.environ.get(env_var, "") + if not prefix: + continue + # Search for lib/cmake/ITK-* (version may vary) + cmake_dir = Path(prefix) / "lib" / "cmake" + if cmake_dir.is_dir(): + for candidate in sorted(cmake_dir.glob("ITK-*")): + itk_config = candidate / "ITKConfig.cmake" + if itk_config.is_file(): + print( + f"Detected conda-installed ITK at {candidate} " + f"(via ${env_var})" + ) + return candidate + return None + + def run(self) -> None: + """Run the full build flow for this Python instance.""" + # Use BuildManager to persist and resume build steps + + # HACK + if self.itk_module_deps: + self._build_module_dependencies() + + # Check for conda/pixi-provided ITK (libitk-wrapping package) + conda_itk_dir = self._detect_conda_itk() + if conda_itk_dir is not None: + # Point the build at the pre-installed ITK — skip compilation + self.cmake_itk_source_build_configurations.set( + "ITK_DIR:PATH", str(conda_itk_dir) + ) + # Set ITK_BINARY_DIR so wheel build and cleanup paths still resolve + self.cmake_itk_source_build_configurations.set( + "ITK_BINARY_DIR:PATH", str(conda_itk_dir) + ) + print( + "Using conda-installed ITK; skipping superbuild and C++ build steps." + ) + + python_package_build_steps: OrderedDict[str, Callable] = OrderedDict( + { + "01_superbuild_support_components": self.build_superbuild_support_components, + "02_build_wrapped_itk_cplusplus": self.build_wrapped_itk_cplusplus, + "03_build_wheels": self.build_itk_python_wheels, + "04_post_build_fixup": self.post_build_fixup, + "05_final_import_test": self.final_import_test, + } + ) + + if conda_itk_dir is not None: + # Skip both superbuild and C++ build when using conda ITK + python_package_build_steps = OrderedDict( + ( + (f"{k}_skipped", (lambda: None)) + if k + in ( + "01_superbuild_support_components", + "02_build_wrapped_itk_cplusplus", + ) + else (k, v) + ) + for k, v in python_package_build_steps.items() + ) + + if self.skip_itk_build: + # Skip these steps if we are in the CI environment + python_package_build_steps = OrderedDict( + ( + ("02_build_wrapped_itk_cplusplus_skipped", (lambda: None)) + if k == "02_build_wrapped_itk_cplusplus" + else (k, v) + ) + for k, v in python_package_build_steps.items() + ) + if self.skip_itk_wheel_build: + python_package_build_steps = OrderedDict( + ( + ("03_build_wheels_skipped", (lambda: None)) + if k == "03_build_wheels" + else (k, v) + ) + for k, v in python_package_build_steps.items() + ) + + if self.module_source_dir is not None: + python_package_build_steps[ + f"06_build_external_module_wheel_{self.module_source_dir.name}" + ] = self.build_external_module_python_wheel + else: + python_package_build_steps["06_build_external_module_wheel_skipped"] = ( + lambda: None + ) + if self.build_itk_tarball_cache: + python_package_build_steps[ + f"07_build_itk_tarball_cache_{self.package_env_config['OS_NAME']}_{self.package_env_config['ARCH']}" + ] = self.build_tarball + + self.dist_dir.mkdir(parents=True, exist_ok=True) + build_report_fn: Path = self.dist_dir / f"build_log_{self.platform_env}.json" + build_manager: BuildManager = BuildManager( + build_report_fn, list(python_package_build_steps.keys()) + ) + build_manager.save() + for build_step_name, build_step_func in python_package_build_steps.items(): + print("=" * 80) + print( + f"Running build step: {build_step_name}: recording status in {build_report_fn}" + ) + # always force_rerun of the tarball step if requested + build_manager.run_step( + build_step_name, + build_step_func, + force_rerun=("tarball_cache" in build_step_name), + ) + build_manager.save() + print( + f"Build step {build_step_name} completed. Edit {build_report_fn} to rerun step." + ) + print("=" * 80) + + def build_superbuild_support_components(self): + """Configure and build the superbuild support components (ITK source, TBB).""" + # ----------------------------------------------------------------------- + # Build required components (optional local ITK source, TBB builds) used to populate the archive cache + + # Build up definitions using the builder + cmake_superbuild_argumets = CMakeArgumentBuilder() + if self.cmake_compiler_configurations: + cmake_superbuild_argumets.update(self.cmake_compiler_configurations.items()) + # Add superbuild-specific flags + cmake_superbuild_argumets.update( + { + "ITKPythonPackage_BUILD_PYTHON:BOOL": "OFF", + "ITKPythonPackage_USE_TBB:BOOL": self.package_env_config["USE_TBB"], + "ITK_SOURCE_DIR:PATH": f"{self.package_env_config['ITK_SOURCE_DIR']}", + "ITK_GIT_TAG:STRING": f"{self.package_env_config['ITK_GIT_TAG']}", + } + ) + # Start from any platform/user-provided defaults + if self.cmake_cmdline_definitions: + cmake_superbuild_argumets.update(self.cmake_cmdline_definitions.items()) + + cmd = [ + self.package_env_config["CMAKE_EXECUTABLE"], + "-G", + "Ninja", + ] + + cmd += cmake_superbuild_argumets.getCMakeCommandLineArguments() + + cmd += [ + "-S", + str(self.package_env_config["IPP_SOURCE_DIR"] / "SuperbuildSupport"), + "-B", + str(self.package_env_config["IPP_SUPERBUILD_BINARY_DIR"]), + ] + + self.echo_check_call(cmd) + self.echo_check_call( + [ + self.package_env_config["CMAKE_EXECUTABLE"], + "--build", + # "--load-average", + # str(self.build_node_cpu_count), + # "--parallel", + # str(self.build_node_cpu_count), + str(self.package_env_config["IPP_SUPERBUILD_BINARY_DIR"]), + ], + ) + + def fixup_wheels(self, lib_paths: str = ""): + """Apply platform-specific fixups to ``itk_core`` wheels for TBB linkage.""" + # TBB library fix-up (applies to itk_core wheel) + tbb_wheel = "itk_core" + for wheel in (self.build_dir_root / "dist").glob(f"{tbb_wheel}*.whl"): + self.fixup_wheel(str(wheel), lib_paths) + + def final_wheel_import_test(self, installed_dist_dir: Path): + """Install and smoke-test all ITK wheels from *installed_dist_dir*. + + Parameters + ---------- + installed_dist_dir : Path + Directory containing the built ``.whl`` files to install and + verify. + """ + exit_status = self.echo_check_call( + [ + self.package_env_config["PYTHON_EXECUTABLE"], + "-m", + "pip", + "install", + "itk", + "--no-cache-dir", + "--no-index", + "-f", + str(installed_dist_dir), + ] + ) + if exit_status == 0: + print("Wheels successfully installed.") + else: + print(f"Failed to install wheels: {exit_status}") + # Basic imports + self.echo_check_call( + [self.package_env_config["PYTHON_EXECUTABLE"], "-c", "import itk;"] + ) + self.echo_check_call( + [ + self.package_env_config["PYTHON_EXECUTABLE"], + "-c", + "import itk; image = itk.Image[itk.UC, 2].New()", + ] + ) + self.echo_check_call( + [ + self.package_env_config["PYTHON_EXECUTABLE"], + "-c", + "import itkConfig; itkConfig.LazyLoading=False; import itk;", + ] + ) + # Full doc tests + self.echo_check_call( + [ + self.package_env_config["PYTHON_EXECUTABLE"], + str( + self.package_env_config["IPP_SOURCE_DIR"] + / "docs" + / "code" + / "test.py" + ), + ] + ) + print("Documentation tests passed.") + + def _pip_uninstall_itk_wildcard(self, python_executable: str | Path): + """Uninstall all installed packages whose name starts with 'itk'. + + pip does not support shell-style wildcards directly for uninstall, so we: + - run 'pip list --format=freeze' + - collect package names whose normalized name starts with 'itk' + - call 'pip uninstall -y ' if any are found + """ + python_executable = str(python_executable) + try: + proc = subprocess.run( + [python_executable, "-m", "pip", "list", "--format=freeze"], + check=True, + capture_output=True, + text=True, + ) + except subprocess.CalledProcessError as e: + print( + f"Warning: failed to list packages with pip at {python_executable}: {e}" + ) + return + + packages = [] + for line in proc.stdout.splitlines(): + line = line.strip() + if not line or line.startswith("#"): + continue + # Formats like 'name==version' or 'name @ URL' + name = line.split("==")[0].split(" @ ")[0].strip() + if name.lower().startswith("itk"): + packages.append(name) + + if packages: + print(f"Uninstalling existing ITK-related packages: {' '.join(packages)}") + # Use echo_check_call for consistent logging/behavior + self.echo_check_call( + [python_executable, "-m", "pip", "uninstall", "-y", *packages] + ) + + def find_unix_exectable_paths( + self, + venv_dir: Path, + ) -> tuple[str, str, str, str, str]: + """Resolve Python interpreter and virtualenv paths on Unix. + + Parameters + ---------- + venv_dir : Path + Root of the Python virtual environment. + + Returns + ------- + tuple[str, str, str, str, str] + ``(python_executable, python_include_dir, python_library, + venv_bin_path, venv_base_dir)``. + + Raises + ------ + FileNotFoundError + If the Python executable does not exist under *venv_dir*. + """ + python_executable = venv_dir / "bin" / "python" + if not python_executable.exists(): + raise FileNotFoundError(f"Python executable not found: {python_executable}") + + # Compute Python include dir using sysconfig for the given interpreter + try: + python_include_dir = ( + subprocess.check_output( + [ + str(python_executable), + "-c", + "import sysconfig; print(sysconfig.get_paths()['include'])", + ], + text=True, + ).strip() + or "" + ) + except Exception as e: + print(f"Failed to compute Python include dir: {e}\n defaulting to empty") + python_include_dir = "" + + # modern CMake with Python3 can infer the library from executable; leave empty + python_library = "" + + # Update PATH + venv_bin_path = venv_dir / "bin" + return ( + str(python_executable), + str(python_include_dir), + str(python_library), + str(venv_bin_path), + str(venv_dir), + ) + + def clone(self): + """Return a deep copy of this instance for building a dependency. + + Uses ``self.__class__`` so the returned object is the same concrete + subclass as the original (e.g. ``LinuxBuildPythonInstance``). + """ + cls = self.__class__ + new = cls.__new__(cls) + new.__dict__ = copy.deepcopy(self.__dict__) + return new + + def venv_paths(self) -> None: + """Populate ``venv_info_dict`` from the pixi-managed Python interpreter. + + Default Unix implementation shared by Linux and macOS. Windows + overrides this method with its own path conventions. + """ + primary_python_base_dir = Path( + self.package_env_config["PYTHON_EXECUTABLE"] + ).parent.parent + ( + python_executable, + python_include_dir, + python_library, + venv_bin_path, + venv_base_dir, + ) = self.find_unix_exectable_paths(primary_python_base_dir) + self.venv_info_dict = { + "python_executable": python_executable, + "python_include_dir": python_include_dir, + "python_library": python_library, + "venv_bin_path": venv_bin_path, + "venv_base_dir": venv_base_dir, + "python_root_dir": primary_python_base_dir, + } + + @abstractmethod + def fixup_wheel( + self, filepath, lib_paths: str = "", remote_module_wheel: bool = False + ): # pragma: no cover - abstract + """Apply platform-specific wheel repairs (auditwheel, delocate, delvewheel). + + Parameters + ---------- + filepath : str + Path to the ``.whl`` file to fix. + lib_paths : str, optional + Additional library search paths (semicolon-delimited on Windows). + remote_module_wheel : bool, optional + True when fixing a wheel for an external remote module. + """ + pass + + @abstractmethod + def build_tarball(self): + """Create a compressed archive of the ITK build tree for caching.""" + pass + + def post_build_cleanup(self) -> None: + """Remove intermediate build artifacts, leaving ``dist/`` intact. + + Actions: + - remove oneTBB-prefix (symlink or dir) + - remove ITKPythonPackage/, tools/, _skbuild/, build/ + - remove top-level *.egg-info + - remove ITK-* build tree and tarballs + - if ITK_MODULE_PREQ is set, remove cloned module dirs + """ + base = Path(self.package_env_config["IPP_SOURCE_DIR"]) + + def rm(tree_path: Path): + try: + _remove_tree(tree_path) + except Exception: + pass + + # 1) unlink oneTBB-prefix if it's a symlink or file + tbb_prefix_dir = base / "oneTBB-prefix" + try: + if tbb_prefix_dir.is_symlink() or tbb_prefix_dir.is_file(): + tbb_prefix_dir.unlink(missing_ok=True) # type: ignore[arg-type] + elif tbb_prefix_dir.exists(): + rm(tbb_prefix_dir) + except Exception: + pass + + # 2) standard build directories + for rel in ("ITKPythonPackage", "tools", "_skbuild", "build"): + rm(base / rel) + + # 3) egg-info folders at top-level + for p in base.glob("*.egg-info"): + rm(p) + + # 4) ITK build tree and tarballs + target_arch = self.package_env_config["ARCH"] + for p in base.glob(f"ITK-*-{self.package_env_config}_{target_arch}"): + rm(p) + + # Tarballs + for p in base.glob(f"ITKPythonBuilds-{self.package_env_config}*.tar.zst"): + rm(p) + + # 5) Optional module prerequisites cleanup (ITK_MODULE_PREQ) + # Format: "InsightSoftwareConsortium/ITKModuleA@v1.0:Kitware/ITKModuleB@sha" + itk_preq = self.package_env_config.get("ITK_MODULE_PREQ") or environ.get( + "ITK_MODULE_PREQ", "" + ) + if itk_preq: + for entry in itk_preq.split(":"): + entry = entry.strip() + if not entry: + continue + try: + module_name = entry.split("@", 1)[0].split("/", 1)[1] + except Exception: + continue + rm(base / module_name) + + @abstractmethod + def prepare_build_env(self) -> None: # pragma: no cover - abstract + """Set up platform-specific build environment and CMake configurations. + + Must populate ``self.venv_info_dict``, configure TBB settings, + and set the ITK binary build directory in + ``self.cmake_itk_source_build_configurations``. + """ + pass + + @abstractmethod + def post_build_fixup(self) -> None: # pragma: no cover - abstract + """Run platform-specific post-build wheel fixups. + + Called after all wheels are built but before the final import + test. Typically invokes ``fixup_wheel`` or ``fixup_wheels``. + """ + pass + + def final_import_test(self) -> None: # pragma: no cover + """Install and smoke-test the built wheels.""" + self.final_wheel_import_test(installed_dist_dir=self.dist_dir) + + @abstractmethod + def discover_python_venvs( + self, platform_os_name: str, platform_architechure: str + ) -> list[str]: + """Return available Python environment names for the given platform. + + Parameters + ---------- + platform_os_name : str + Operating system identifier. + platform_architechure : str + CPU architecture identifier. + + Returns + ------- + list[str] + Sorted list of discovered environment names. + """ + pass + + @staticmethod + def _update_module_itk_deps(pyproject_path: Path, itk_version: str) -> bool: + """Rewrite ITK dependency pins in a remote module's pyproject.toml. + + Replaces hard-coded ITK sub-package version pins (e.g. + ``itk-io == 5.4.*``) with a pin matching the ITK version being + built against (e.g. ``itk-io >= 5.4``). This ensures that + wheels produced for ITK 6 can be installed alongside ITK 6 + packages without pip dependency conflicts. + + .. note:: Strategy 1 (build-time rewrite) — interim solution. + + This approach rewrites the module's pyproject.toml on disk, + builds the wheel, then restores the original. It works today + with zero changes to remote modules but is inherently fragile + (regex-based, modifies the source tree). + + **Plan to migrate to Strategy 3 (scikit-build-core dynamic + metadata provider):** + + 1. Create a small installable package ``itk-build-metadata`` + that implements the scikit-build-core dynamic metadata + provider interface (see scikit-build-core docs: + ``tool.scikit-build.metadata..provider``). + + 2. The provider inspects the build environment at wheel-build + time to discover the ITK version — either from the + ``ITK_PACKAGE_VERSION`` env var (set by this build system), + from ``ITKConfig.cmake`` on ``CMAKE_PREFIX_PATH``, or from + an already-installed ``itk-core`` package. + + 3. It emits the correct ``Requires-Dist`` entries (e.g. + ``itk-io >= 5.4``) into the wheel metadata without + touching ``pyproject.toml`` on disk at all. + + 4. Remote modules opt in by declaring dynamic dependencies:: + + [project] + dynamic = ["dependencies"] + + [tool.scikit-build.metadata.dependencies] + provider = "itk_build_metadata" + provider-path = "." # or from installed package + + 5. Roll out incrementally: update ITKModuleTemplate first, + then migrate existing modules via the ``/update-itk-deps`` + skill (in REMOTE_MODULES/.claude/skills/). Modules that + have not migrated continue to work via this Strategy 1 + fallback, so both approaches coexist during the transition. + + 6. Once all ~60 remote modules have adopted Strategy 3, + this method can be removed. + + Parameters + ---------- + pyproject_path : Path + Path to the module's ``pyproject.toml``. + itk_version : str + The ITK PEP 440 version string being built (e.g. ``6.0.0b2``). + Used to compute the minimum major version for the ``>=`` pin. + + Returns + ------- + bool + *True* if any dependency was rewritten. + """ + import re + + try: + import tomllib + except ModuleNotFoundError: + import tomli as tomllib # Python < 3.11 + + with open(pyproject_path, "rb") as f: + pyproject_data = tomllib.load(f) + + # --- Strategy 3: module declares dynamic dependencies ----------------- + dynamic_fields = ( + pyproject_data.get("project", {}).get("dynamic", []) + ) + if "dependencies" in dynamic_fields: + # The module has opted into dynamic dependency resolution. + # Set ITK_PACKAGE_VERSION in the environment so the + # scikit-build-core metadata provider (itk-build-metadata) + # can emit the correct Requires-Dist at build time. + os.environ["ITK_PACKAGE_VERSION"] = itk_version + print( + f"Strategy 3: {pyproject_path.name} declares " + f"dynamic=[\"dependencies\"]; set ITK_PACKAGE_VERSION=" + f"{itk_version} for metadata provider" + ) + return False # no file modification needed + + # --- Strategy 1: build-time rewrite (fallback) ------------------------ + text = pyproject_path.read_text(encoding="utf-8") + + # Only rewrite ITK *base* sub-packages whose versions are tied to + # the ITK release. Remote module cross-deps (e.g. + # itk-meshtopolydata == 0.12.*) are versioned independently and + # must NOT be rewritten — flag them for manual review instead. + _ITK_BASE_PACKAGES = ( + "itk-core", + "itk-numerics", + "itk-io", + "itk-filtering", + "itk-registration", + "itk-segmentation", + ) + _base_pkg_alt = "|".join(re.escape(p) for p in _ITK_BASE_PACKAGES) + pattern = re.compile( + rf'"({_base_pkg_alt})\s*==\s*[\d]+\.[\d]+\.\*"' + ) + + # Warn about pinned remote-module cross-deps that may also need + # attention but should not be auto-rewritten. + cross_dep_pattern = re.compile( + r'"(itk-[a-z][a-z0-9-]*)\s*==\s*[\d]+\.[\d]+\.\*"' + ) + for m in cross_dep_pattern.finditer(text): + pkg = m.group(1) + if pkg not in _ITK_BASE_PACKAGES: + print( + f" WARNING: {pyproject_path.name} pins remote module " + f"cross-dep {m.group(0)} — review manually" + ) + + # The minimum version floor is the MAJOR.MINOR of the ITK version + # being built. A wheel compiled against ITK 6.0 requires ITK >= 6.0 + # at install time; one compiled against ITK 5.4 requires >= 5.4. + # The build system itself supports building against any ITK from + # v5.4 through the latest (v5.5, v6.0, v7.1, etc.) — the floor + # simply reflects which ITK the wheel was actually linked against. + parts = itk_version.split(".") + try: + min_floor = f"{parts[0]}.{parts[1]}" + except IndexError: + min_floor = itk_version + + changed = False + def _replace(m: re.Match) -> str: + nonlocal changed + changed = True + pkg = m.group(1) + return f'"{pkg} >= {min_floor}"' + + new_text = pattern.sub(_replace, text) + if changed: + pyproject_path.write_text(new_text, encoding="utf-8") + print( + f"Strategy 1: Updated ITK dependency pins in {pyproject_path} " + f"(>= {min_floor} for ITK {itk_version})" + ) + return changed + + def build_external_module_python_wheel(self): + """Build a wheel for an external ITK remote module via scikit-build-core.""" + self.module_source_dir = Path(self.module_source_dir) + out_dir = self.module_source_dir / "dist" + out_dir.mkdir(parents=True, exist_ok=True) + + # Dynamically update ITK dependency pins to match the version being built. + # Back up the original pyproject.toml so the working tree is restored + # after the wheel is produced. + module_pyproject = self.module_source_dir / "pyproject.toml" + pyproject_orig = module_pyproject.with_suffix(".toml.orig") + pyproject_whl = module_pyproject.with_suffix(".toml.whl") + deps_rewritten = False + if module_pyproject.is_file(): + itk_ver = self.package_env_config.get("ITK_PACKAGE_VERSION", "") + if itk_ver: + shutil.copy2(module_pyproject, pyproject_orig) + deps_rewritten = self._update_module_itk_deps( + module_pyproject, itk_ver + ) + + # Ensure venv tools are first in PATH + py_exe = str(self.package_env_config["PYTHON_EXECUTABLE"]) # Python3_EXECUTABLE + + # Compute Python include directory (Python3_INCLUDE_DIR) + py_include = self.venv_info_dict.get("python_include_dir", "") + if not py_include: + try: + py_include = ( + subprocess.check_output( + [ + py_exe, + "-c", + "import sysconfig; print(sysconfig.get_paths()['include'])", + ], + text=True, + ).strip() + or "" + ) + except Exception: + py_include = "" + + # Determine platform-specific settings (macOS) + config_settings: dict[str, str] = {} + + # ITK build path for external modules: prefer configured ITK binary dir + itk_build_path = self.cmake_itk_source_build_configurations.get( + "ITK_BINARY_DIR:PATH", + "", + ) + + # wheel.py-api for stable ABI when Python >= 3.11 + try: + py_minor = int( + subprocess.check_output( + [py_exe, "-c", "import sys; print(sys.version_info.minor)"], + text=True, + ).strip() + ) + except Exception: + py_minor = 0 + wheel_py_api = f"cp3{py_minor}" if py_minor >= 11 else "" + + # Base build command + cmd = [ + py_exe, + "-m", + "build", + "--verbose", + "--wheel", + "--outdir", + str(out_dir), + "--no-isolation", + "--skip-dependency-check", + f"--config-setting=cmake.build-type={self.package_env_config['BUILD_TYPE']}", + ] + + # Collect scikit-build CMake definitions + defs = CMakeArgumentBuilder() + defs.update(self.cmake_compiler_configurations.items()) + # Propagate macOS specific defines if any were set above + for k, v in config_settings.items(): + defs.set(k, v) + + # Required defines for external module build + if itk_build_path: + defs.set("ITK_DIR:PATH", str(itk_build_path)) + defs.set("CMAKE_INSTALL_LIBDIR:STRING", "lib") + defs.set("WRAP_ITK_INSTALL_COMPONENT_IDENTIFIER:STRING", "PythonWheel") + defs.set("PY_SITE_PACKAGES_PATH:PATH", ".") + defs.set("BUILD_TESTING:BOOL", "OFF") + defs.set("Python3_EXECUTABLE:FILEPATH", py_exe) + if py_include: + defs.set("Python3_INCLUDE_DIR:PATH", py_include) + + # Pass Python library paths when explicitly known (Windows) + py_library = self.venv_info_dict.get("python_library", "") + if py_library: + defs.set("Python3_LIBRARY:FILEPATH", str(py_library)) + py_sabi_library = self.venv_info_dict.get("python_sabi_library", "") + if py_sabi_library: + defs.set("Python3_SABI_LIBRARY:FILEPATH", str(py_sabi_library)) + + # Allow command-line cmake -D overrides to win last + if self.cmake_cmdline_definitions: + defs.update(self.cmake_cmdline_definitions.items()) + + # Append all cmake.define entries to the build cmd + cmd += defs.getPythonBuildCommandLineArguments() + + # Stable ABI setting if applicable + if wheel_py_api: + cmd += [f"--config-setting=wheel.py-api={wheel_py_api}"] + + # Module source directory to build + cmd += [self.module_source_dir] + + try: + self.echo_check_call(cmd) + + # Post-process produced wheels (e.g., delocate on macOS x86_64) + for wheel in out_dir.glob("*.whl"): + self.fixup_wheel(str(wheel), remote_module_wheel=True) + finally: + # Restore original pyproject.toml so the working tree stays clean + if deps_rewritten and pyproject_orig.is_file(): + shutil.copy2(module_pyproject, pyproject_whl) + shutil.move(str(pyproject_orig), str(module_pyproject)) + print( + f"Restored {module_pyproject} " + f"(modified version saved as {pyproject_whl.name})" + ) + + def build_itk_python_wheels(self): + """Build all ITK Python wheels listed in ``WHEEL_NAMES.txt``.""" + # Build wheels + for wheel_name in self.wheel_names: + print("#") + print(f"# Build ITK wheel {wheel_name} from {self.wheel_names}") + print("#") + # Configure pyproject.toml + wheel_configbuild_dir_root: Path = ( + self.build_dir_root + / "wheelbuilds" + / f"{wheel_name}_{self.get_pixi_environment_name()}" + ) + wheel_configbuild_dir_root.mkdir(parents=True, exist_ok=True) + configure_one_pyproject_file( + str(self.ipp_dir / "scripts"), + self.package_env_config, + wheel_configbuild_dir_root, + wheel_name, + ) + + # Generate wheel using + cmd = [ + str(self.package_env_config["PYTHON_EXECUTABLE"]), + "-m", + "build", + "--verbose", + "--wheel", + "--outdir", + str(self.build_dir_root / "dist"), + "--no-isolation", + "--skip-dependency-check", + f"--config-setting=cmake.build-type={self.package_env_config['BUILD_TYPE']}", + f"--config-setting=cmake.source-dir={self.package_env_config['IPP_SOURCE_DIR'] / 'BuildWheelsSupport'}", + f"--config-setting=build-dir={wheel_configbuild_dir_root/'build'}", + ] + # Build scikit-build defines via builder + scikitbuild_cmdline_args = CMakeArgumentBuilder() + scikitbuild_cmdline_args.update(self.cmake_compiler_configurations.items()) + scikitbuild_cmdline_args.update( + self.cmake_itk_source_build_configurations.items() + ) + scikitbuild_cmdline_args.update( + { + "ITKPythonPackage_USE_TBB:BOOL": self.package_env_config["USE_TBB"], + "ITKPythonPackage_ITK_BINARY_REUSE:BOOL": "ON", + "ITKPythonPackage_WHEEL_NAME:STRING": f"{wheel_name}", + "DOXYGEN_EXECUTABLE:FILEPATH": f"{self.package_env_config['DOXYGEN_EXECUTABLE']}", + } + ) + + if ( + self.cmake_cmdline_definitions + ): # Do last to override with command line items + scikitbuild_cmdline_args.update(self.cmake_cmdline_definitions.items()) + # Append all cmake.define entries + cmd += scikitbuild_cmdline_args.getPythonBuildCommandLineArguments() + # The location of the generated pyproject.toml file + cmd += [wheel_configbuild_dir_root] + self.echo_check_call(cmd) + + # Remove unnecessary files for building against ITK + if self.cleanup: + bp = Path( + self.cmake_itk_source_build_configurations["ITK_BINARY_DIR:PATH"] + ) + for p in bp.rglob("*"): + if p.is_file() and p.suffix in [".cpp", ".xml", ".obj", ".o"]: + try: + p.unlink() + except OSError: + pass + _remove_tree(bp / "Wrapping" / "Generators" / "CastXML") + + def build_wrapped_itk_cplusplus(self): + """Configure and build the ITK C++ libraries with Python wrapping.""" + # Clean up previous invocations + if ( + self.cleanup + and Path( + self.cmake_itk_source_build_configurations["ITK_BINARY_DIR:PATH"] + ).exists() + ): + _remove_tree( + Path(self.cmake_itk_source_build_configurations["ITK_BINARY_DIR:PATH"]) + ) + + print("#") + print("# START-Build ITK C++") + print("#") + + # Build ITK python + cmd = [ + self.package_env_config["CMAKE_EXECUTABLE"], + "-G", + "Ninja", + ] + # Collect all -D definitions via builder + defs = CMakeArgumentBuilder() + defs.update(self.cmake_compiler_configurations.items()) + defs.update(self.cmake_itk_source_build_configurations.items()) + # NOTE Do cmake_cmdline_definitions last so they override internal defaults + defs.update(self.cmake_cmdline_definitions.items()) + cmd += defs.getCMakeCommandLineArguments() + cmd += [ + "-S", + self.package_env_config["ITK_SOURCE_DIR"], + "-B", + self.cmake_itk_source_build_configurations["ITK_BINARY_DIR:PATH"], + ] + self.echo_check_call(cmd) + self.echo_check_call( + [ + self.package_env_config["NINJA_EXECUTABLE"], + f"-j{self.build_node_cpu_count}", + f"-l{self.build_node_cpu_count}", + "-C", + self.cmake_itk_source_build_configurations["ITK_BINARY_DIR:PATH"], + ] + ) + print("# FINISHED-Build ITK C++") + + def _build_module_dependencies(self): + """ + Build prerequisite ITK external modules, mirroring the behavior of + the platform shell scripts that use the ITK_MODULE_PREQ environment. + + Accepted formats in self.itk_module_deps (colon-delimited): + - "MeshToPolyData@v0.10.0" -> defaults to + "InsightSoftwareConsortium/ITKMeshToPolyData@v0.10.0" + - "InsightSoftwareConsortium/ITKMeshToPolyData@v0.10.0" + + For each dependency, clone the repository, checkout the given tag, + invoke the platform download-cache-and-build script, then copy + headers and wrapping input files into the current module tree + (include/ and wrapping/), similar to the bash implementations. + """ + + if len(self.itk_module_deps) == 0: + return + print(f"Building module dependencies: {self.itk_module_deps}") + self.module_dependencies_root_dir.mkdir(parents=True, exist_ok=True) + + # Normalize entries to "Org/Repo@Tag" + def _normalize(entry: str) -> str: + entry = entry.strip() + if not entry: + return "" + if "/" in entry: + # Already Org/Repo@Tag + return entry + # Short form: Name@Tag -> InsightSoftwareConsortium/ITKName@Tag + try: + name, tag = entry.split("@", 1) + except ValueError: + # If no tag, pass-through (unexpected) + return entry + repo = f"ITK{name}" + return f"InsightSoftwareConsortium/{repo}@{tag}" + + # Ensure working directories exist + module_root = Path(self.module_source_dir).resolve() + include_dir = module_root / "include" + wrapping_dir = module_root / "wrapping" + include_dir.mkdir(parents=True, exist_ok=True) + wrapping_dir.mkdir(parents=True, exist_ok=True) + + dep_entries = [e for e in (s for s in self.itk_module_deps.split(":")) if e] + normalized = [_normalize(e) for e in dep_entries] + normalized = [e for e in normalized if e] + + # Build each dependency in order + for _current_entry, entry in enumerate(normalized): + if len(entry) == 0: + continue + print(f"Get dependency module information for {entry}") + org = entry.split("/", 1)[0] + repo_tag = entry.split("/", 1)[1] + repo = repo_tag.split("@", 1)[0] + tag = repo_tag.split("@", 1)[1] if "@" in repo_tag else "" + + upstream = f"https://github.com/{org}/{repo}.git" + dependant_module_clone_dir = ( + self.module_dependencies_root_dir / repo + if self.module_dependencies_root_dir + else module_root / repo + ) + if not dependant_module_clone_dir.exists(): + self.echo_check_call( + ["git", "clone", upstream, dependant_module_clone_dir] + ) + + # Checkout requested tag + self.echo_check_call( + [ + "git", + "-C", + dependant_module_clone_dir, + "fetch", + "--all", + "--tags", + ] + ) + if tag: + self.echo_check_call( + ["git", "-C", dependant_module_clone_dir, "checkout", tag] + ) + + if (dependant_module_clone_dir / "setup.py").exists(): + msg: str = ( + f"Old sci-kit-build with setup.py is no longer supported for {dependant_module_clone_dir} at {tag}" + ) + raise RuntimeError(msg) + + # Clone the current build environment and modify for the current module + dependent_module_build_setup = self.clone() + dependent_module_build_setup.module_source_dir = Path( + dependant_module_clone_dir + ) + dependent_module_build_setup.itk_module_deps = None # Prevent recursion + dependent_module_build_setup.run() + + # After building dependency, copy includes and wrapping files + # 1) Top-level include/* -> include/ + dep_include = dependant_module_clone_dir / "include" + if dep_include.exists(): + for src in dep_include.rglob("*"): + if src.is_file(): + rel = src.relative_to(dep_include) + dst = include_dir / rel + dst.parent.mkdir(parents=True, exist_ok=True) + try: + shutil.copy2(src, dst) + except Exception: + pass + + # 2) Any */build/*/include/* -> include/ + for sub in dependant_module_clone_dir.rglob("*build*/**/include"): + if sub.is_dir(): + for src in sub.rglob("*"): + if src.is_file(): + rel = src.relative_to(sub) + dst = include_dir / rel + dst.parent.mkdir(parents=True, exist_ok=True) + try: + shutil.copy2(src, dst) + except Exception: + pass + + # 3) Wrapping templates (*.in, *.init) -> wrapping/ + dep_wrapping = dependant_module_clone_dir / "wrapping" + if dep_wrapping.exists(): + for pattern in ("*.in", "*.init"): + for src in dep_wrapping.rglob(pattern): + if src.is_file(): + dst = wrapping_dir / src.name + try: + shutil.copy2(src, dst) + except Exception: + pass + + def create_posix_tarball(self): + """Create a compressed tarball of the ITK Python build tree. + + Mirrors the historical scripts/*-build-tarball.sh behavior: + - zstd compress with options (-10 -T6 --long=31) + + Warns if directory structure doesn't match expected layout for GitHub Actions. + """ + arch_postfix: str = f"{self.package_env_config['ARCH']}" + # Fixup platform name for macOS, eventually need to standardize on macosx naming convention + platform_name: str = get_default_platform_build().split("-")[0] + tar_name: str = f"ITKPythonBuilds-{platform_name}-{arch_postfix}.tar" + itk_packaging_reference_dir = self.build_dir_root.parent + + tar_path: Path = itk_packaging_reference_dir / tar_name + zst_path: Path = itk_packaging_reference_dir / f"{tar_name}.zst" + + itk_resources_build_dir: Path = self.build_dir_root + ipp_source_dir: Path = self.package_env_config["IPP_SOURCE_DIR"] + + # Validate directory structure and determine tarball strategy + issues = [] + + # Try to use relative paths first + try: + rel_build = itk_resources_build_dir.relative_to(itk_packaging_reference_dir) + rel_ipp = ipp_source_dir.relative_to(itk_packaging_reference_dir) + except ValueError: + # Fall back to absolute paths + rel_build = itk_resources_build_dir + rel_ipp = ipp_source_dir + itk_packaging_reference_dir = Path( + "/" + ) # Tar from root when using absolute paths + + if itk_resources_build_dir.parent != ipp_source_dir.parent: + issues.append("Build and source dirs are not siblings") + + if ipp_source_dir.name != "ITKPythonPackage": + issues.append( + f"Source dir is '{ipp_source_dir.name}', expected 'ITKPythonPackage'" + ) + + # Issue consolidated warning for compatibility issues + if issues: + print("\n" + "=" * 70) + print("WARNING: Tarball will NOT be compatible with GitHub Actions") + print("=" * 70) + for issue in issues: + print(f" * {issue}") + print( + "\nExpected structure: /{ITKPythonPackage, ITKPythonPackage-build}" + ) + print(f"Current: Build={itk_resources_build_dir}") + print(f" Source={ipp_source_dir}") + print( + "\nTarball will be created for local reuse but may not work in CI/CD." + ) + print("=" * 70 + "\n") + + # Build tarball include paths + tarball_include_paths = [ + str(rel_build), + str(rel_ipp), + ] + + if tar_path.exists(): + print(f"Removing existing tarball {tar_path}") + tar_path.unlink() + if zst_path.exists(): + print(f"Removing existing zstd tarball {zst_path}") + zst_path.unlink() + + # Create tarball + self.echo_check_call( + [ + "tar", + "-C", + str(itk_packaging_reference_dir), + "-cf", + str(tar_path), + "--exclude=*.o", + "--exclude=*.whl", # Do not include built wheels + "--exclude=*/dist/*", # Do not include the dist whl output directory + "--exclude=*/wheelbuilds/*", # Do not include the wheelbuild support directory + "--exclude=*/__pycache__/*", # Do not include __pycache__ + "--exclude=install_manifest_*.txt", # Do not include install manifest files + "--exclude=._*", # Exclude mac dot files + "--exclude=*/.git/*", + "--exclude=*/.idea/*", + "--exclude=*/.pixi/*", + "--exclude=*/castxml_inputs/*", + "--exclude=*/Wrapping/Modules/*", + *tarball_include_paths, + ] + ) + + # Compress with zstd + self.echo_check_call( + [ + "zstd", + "-f", + "-10", + "-T6", + "--long=31", + str(tar_path), + "-o", + str(zst_path), + ] + ) + + print(f"Tarball created: {zst_path}") + if issues: + print("Compatibility warnings above - review before using in CI/CD") + + def get_pixi_environment_name(self): + """Return the pixi environment name for this build instance. + + The pixi environment name is the same as the platform_env and + is related to the environment setups defined in pixi.toml + in the root of this git directory that contains these scripts. + """ + return self.platform_env + + def echo_check_call( + self, + cmd: list[str | Path] | tuple[str | Path] | str | Path, + use_pixi_env: bool = True, + env=None, + **kwargs: dict, + ) -> int: + """Print the command, then run subprocess.check_call. + + Parameters + ---------- + cmd : + Command to execute, same as subprocess.check_call. + **kwargs : + Additional keyword arguments forwarded to subprocess.check_call. + """ + + pixi_environment: str = self.get_pixi_environment_name() + pixi_executable: Path = self.package_env_config["PIXI_EXECUTABLE"] + pixi_run_preamble: list[str] = [] + pixi_run_dir: Path = self.ipp_dir + pixi_env: dict[str, str] = os.environ.copy() + if env is not None: + pixi_env.update(env) + pixi_env.update( + { + "PIXI_HOME": str(pixi_run_dir / ".pixi"), + } + ) + # if self.pa == "windows": + # pixi_env.update( + # { + # "TEMP": "C:\Temp", + # "TMP": "C:\Temp", + # } + # ) + + if pixi_environment and use_pixi_env: + pixi_run_preamble = [ + str(pixi_executable), + "run", + "-e", + pixi_environment, + "--", + ] + + # convert all items to strings (i.e. Path() to str) + cmd = pixi_run_preamble + [str(c) for c in cmd] + # Prepare a friendly command-line string for display + try: + if isinstance(cmd, list | tuple): + display_cmd = " ".join(cmd) + else: + display_cmd = str(cmd) + except Exception as e: + display_cmd = f"{str(cmd)}\nERROR: {e}" + sys.exit(1) + print(f">>Start Running: cd {pixi_run_dir} && {display_cmd}") + print("^" * 60) + print(cmd) + print("^" * 60) + print(kwargs) + print("^" * 60) + process_completion_info: subprocess.CompletedProcess = ( + run_commandLine_subprocess(cmd, env=pixi_env, cwd=pixi_run_dir, **kwargs) + ) + cmd_return_status: int = process_completion_info.returncode + print("^" * 60) + print(f"< dict[str, str]: + """Collect GitHub Actions environment variables for remote module builds. + + The following environment variables are defined by the + ``ITKRemoteModuleBuildTestPackageAction`` GitHub Action. Variables + marked *active* are read from the environment with a default + fallback; those marked *not used* are documented here for + cross-reference but are no longer consumed at runtime. + + Environment Variables + --------------------- + ITK_PACKAGE_VERSION : str (active) + PEP 440 version string for ITK packages. + GitHub Action source: ``inputs.itk-wheel-tag``. + Default ``"auto"`` triggers automatic version computation. + ITKPYTHONPACKAGE_TAG : str (not used — GitHub Actions scripts only) + Git tag for ITKPythonPackage checkout. + GitHub Action source: ``inputs.itk-python-package-tag``. + ITKPYTHONPACKAGE_ORG : str (not used — GitHub Actions scripts only) + GitHub organization owning ITKPythonPackage. + GitHub Action source: ``inputs.itk-python-package-org``. + ITK_MODULE_PREQ : str (active) + Colon-delimited list of remote module dependencies. + GitHub Action source: ``inputs.itk-module-deps``. + CMAKE_OPTIONS : str (active) + Extra options forwarded to CMake. + GitHub Action source: ``inputs.cmake-options``. + MANYLINUX_PLATFORM : str (not used — computed internally) + Full manylinux platform string (e.g. ``"manylinux_2_28-x64"``). + GitHub Action source: ``matrix.manylinux-platform``. + MANYLINUX_VERSION : str (active) + Manylinux specification (e.g. ``"_2_28"``). Historically + computed as the first part of ``MANYLINUX_PLATFORM``. + TARGET_ARCH : str (not used — computed internally) + Target architecture (e.g. ``"x64"``). Historically computed + as the second part of ``MANYLINUX_PLATFORM``. + MACOSX_DEPLOYMENT_TARGET : str (active) + Minimum macOS version for wheel compatibility. + GitHub Action source: ``inputs.macosx-deployment-target``. + Default ``"10.7"`` is outdated but provides backward + compatibility. + + Returns + ------- + dict[str, str] + A mapping of active configuration keys to their values, sourced + from environment variables with sensible defaults. + """ + env_defaults: dict[str, str] = { + "ITK_PACKAGE_VERSION": "auto", + "ITK_MODULE_PREQ": "", + "CMAKE_OPTIONS": "", + "MANYLINUX_VERSION": "", + "MACOSX_DEPLOYMENT_TARGET": "10.7", + } + return {key: os.environ.get(key, default) for key, default in env_defaults.items()} + + +def in_pixi_env() -> bool: + """Check whether the process is running inside a pixi environment. + + Returns + ------- + bool + True if both ``PIXI_ENVIRONMENT_NAME`` and ``PIXI_PROJECT_ROOT`` + are set in the environment. + """ + return "PIXI_ENVIRONMENT_NAME" in os.environ and "PIXI_PROJECT_ROOT" in os.environ + + +def get_effective_command_line( + parser: argparse.ArgumentParser, args: argparse.Namespace +) -> str: + """Reconstruct a reproducible command line from parsed arguments. + + Parameters + ---------- + parser : argparse.ArgumentParser + The argument parser used to parse *args*. + args : argparse.Namespace + Parsed command-line arguments. + + Returns + ------- + str + A shell-safe command string suitable for logging or re-execution + inside a pixi environment. + """ + pixi_executable: str = os.environ.get("PIXI_EXE", "pixi") + effective_command = [ + pixi_executable, + "run", + "-e", + args.platform_env, + "--", + sys.executable, + sys.argv[0], + ] + for action in parser._actions: + if isinstance(action, argparse._HelpAction): + continue + dest = action.dest + value = getattr(args, dest, None) + if value is None: + continue + if action.option_strings: + option_string = action.option_strings[0] + if isinstance(action, argparse._StoreTrueAction): + if value: + effective_command.append(option_string) + elif isinstance(action, argparse._StoreFalseAction): + if not value: + effective_command.append(option_string) + else: + if isinstance(value, list): + if value: + effective_command.append(option_string) + effective_command.extend([str(v) for v in value]) + else: + effective_command.append(option_string) + effective_command.append(str(value)) + else: + if isinstance(value, list): + effective_command.extend([str(v) for v in value]) + else: + effective_command.append(str(value)) + return shlex.join(effective_command) + + +def build_wheels_main() -> None: + """Entry point: parse arguments, configure, and run the wheel build.""" + os_name, arch = detect_platform() + ipp_script_dir: Path = Path(__file__).parent + ipp_dir: Path = ipp_script_dir.parent + if (ipp_dir / ".pixi" / "bin").exists(): + os.environ["PATH"] = ( + str(ipp_dir / ".pixi" / "bin") + os.pathsep + os.environ["PATH"] + ) + + remote_module_build_dict = remotemodulebuildandtestaction() + parser = argparse.ArgumentParser( + description="Driver script to build ITK Python wheels." + ) + parser.add_argument( + "--platform-env", + default=get_default_platform_build("py311"), + help=( + """A platform environment name or path: + linux-py310, linux-py311, + manylinux228-py310, manylinux228-py311, + windows-py310, windows-py311, + macosx-py310, macosx-py311 + """ + ), + ) + parser.add_argument( + "--cleanup", + dest="cleanup", + action="store_true", + help=""" + 'ITK_MODULE_NO_CLEANUP': Option to skip cleanup steps. + =1 <- Leave temporary build files in place after completion, 0 <- remove temporary build files + """, + ) + parser.add_argument( + "--lib-paths", + nargs=1, + default="", + help=( + "Windows only: semicolon-delimited library directories for delvewheel to include in module wheel" + ), + ) + _cmake_options_default = remote_module_build_dict["CMAKE_OPTIONS"] + parser.add_argument( + "cmake_options", + nargs="*", + default=shlex.split(_cmake_options_default) if _cmake_options_default else [], + help="Extra options to pass to CMake, e.g. -DBUILD_SHARED_LIBS:BOOL=OFF.\n" + " These will override defaults if duplicated", + ) + parser.add_argument( + "--module-source-dir", + type=str, + default=None, + help="Path to the (remote) module source directory to build.", + ) + parser.add_argument( + "--module-dependencies-root-dir", + type=str, + default=None, + help="Path to the root directory for module dependencies.\n" + + "This is the path where a remote module dependencies (other remote modules)\n" + + "are searched for, or automatically git cloned to.", + ) + parser.add_argument( + "--itk-module-deps", + type=str, + default=remote_module_build_dict["ITK_MODULE_PREQ"], + help="Semicolon-delimited list of a remote modules dependencies.\n" + + "'gitorg/repo@tag:gitorg/repo@tag:gitorg/repo@tag'\n" + + "These are set in ITKRemoteModuleBuildTestPackageAction:itk-module-deps github actions." + + "and were historically set as an environment variable ITK_MODULE_PREQ.", + ) + + parser.add_argument( + "--build-itk-tarball-cache", + dest="build_itk_tarball_cache", + action="store_true", + default=False, + help="Build an uploadable tarball. The tarball can be used as a cache for remote module builds.", + ) + parser.add_argument( + "--no-build-itk-tarball-cache", + dest="build_itk_tarball_cache", + action="store_false", + help="Do not build an uploadable tarball. The tarball can be used as a cache for remote module builds.", + ) + + # set the default build_dir_root to a very short path on Windows to avoid path too long errors + default_build_dir_root = ( + ipp_dir.parent / "ITKPythonPackage-build" + if os_name != "windows" + else Path("C:/") / "BDR" + ) + parser.add_argument( + "--build-dir-root", + type=str, + default=f"{default_build_dir_root}", + help="The root of the build resources.", + ) + parser.add_argument( + "--manylinux-version", + type=str, + default=remote_module_build_dict["MANYLINUX_VERSION"], + help="default manylinux version (_2_28, _2_34, ...), if empty, build native linux instead of cross compiling", + ) + + parser.add_argument( + "--itk-git-tag", + type=str, + default=os.environ.get( + "ITK_GIT_TAG", os.environ.get("ITK_PACKAGE_VERSION", "main") + ), + help=""" + - 'ITK_GIT_TAG': Tag/branch/hash for the ITK source code to use in packaging. + Which ITK git tag/hash/branch to use as reference for building wheels/modules + https://github.com/InsightSoftwareConsortium/ITK.git@${ITK_GIT_TAG} + Examples: v5.4.0, v5.2.1.post1, 0ffcaed12552, my-testing-branch + See available release tags at https://github.com/InsightSoftwareConsortium/ITKPythonBuilds/tags + """, + ) + + # set the default build_dir_root to a very short path on Windows to avoid path too long errors + default_itk_source_dir = ( + ipp_dir.parent / "ITKPythonPackage-build" / "ITK" + if os_name != "windows" + else Path("C:/") / "BDR" / "ITK" + ) + parser.add_argument( + "--itk-source-dir", + type=str, + default=os.environ.get("ITK_SOURCE_DIR", str(default_itk_source_dir)), + help=""" + - 'ITK_SOURCE_DIR': When building different 'flavor' of ITK python packages + on a given platform, explicitly setting the ITK_SOURCE_DIR options allow to + speed up source-code downloads by re-using an existing repository. + If the requested directory does not exist, manually clone and checkout ${ITK_GIT_TAG}""", + ) + + parser.add_argument( + "--itk-package-version", + type=str, + default=remote_module_build_dict["ITK_PACKAGE_VERSION"], + help=""" + - 'ITK_PACKAGE_VERSION' A valid PEP440 version string for the itk packages generated. + The default is to automatically generate a PEP440 version automatically based on relative + versioning from the latest tagged release. + (in github action ITKRemoteModuleBuildTestPackage itk-wheel-tag is used to set this value) + """, + ) + + if os_name == "darwin": + parser.add_argument( + "--macosx-deployment-target", + type=str, + default=remote_module_build_dict["MACOSX_DEPLOYMENT_TARGET"], + help=""" + The MacOSX deployment target to use for building wheels. + """, + ) + + parser.add_argument( + "--use-sudo", + action="store_true", + dest="use_sudo", + default=False, + help=""" + - Enable if running docker requires sudo privileges + """, + ) + parser.add_argument( + "--no-use-sudo", + action="store_false", + dest="use_sudo", + help=""" + - Enable if running docker requires sudo privileges + """, + ) + + parser.add_argument( + "--use-ccache", + action="store_true", + dest="use_ccache", + default=False, + help=""" + - Option to indicate that ccache should be used + """, + ) + parser.add_argument( + "--no-use-ccache", + action="store_false", + dest="use_ccache", + help=""" + - Option to indicate that ccache should not be used + """, + ) + + parser.add_argument( + "--skip-itk-build", + action="store_true", + dest="skip_itk_build", + default=False, + help=""" + - Option to skip the ITK C++ build step (Step 2) + """, + ) + + parser.add_argument( + "--no-skip-itk-build", + action="store_false", + dest="skip_itk_build", + help=""" + - Option to not skip the ITK C++ build step (Step 2) + """, + ) + + parser.add_argument( + "--skip-itk-wheel-build", + action="store_true", + dest="skip_itk_wheel_build", + default=False, + help=""" + - Option to skip the ITK wheel build step (Step 3) + """, + ) + + parser.add_argument( + "--no-skip-itk-wheel-build", + action="store_false", + dest="skip_itk_wheel_build", + help=""" + - Option to not skip the ITK wheel build step (Step 3) + """, + ) + + args = parser.parse_args() + + # Historical dist_dir name for compatibility with ITKRemoteModuleBuildTestPackageAction + _ipp_dir_path: Path = Path(__file__).resolve().parent.parent + dist_dir: Path = Path(args.build_dir_root) / "dist" + + # Platform detection + binary_ext: str = ".exe" if os_name == "windows" else "" + env_bin_dir: str = "Scripts" if os_name == "windows" else "bin" + + env_path = _ipp_dir_path / ".pixi" / "envs" / args.platform_env + # multiple locations the executables can be at on Windows + env_subdirs = ( + [env_bin_dir, "Library/bin"] if os_name == "windows" else [env_bin_dir] + ) + + os.environ["PATH"] = os.pathsep.join( + [ + *[str(env_path / d) for d in env_subdirs], + str(_ipp_dir_path / ".pixi" / "bin"), + os.environ.get("PATH", ""), + ] + ) + pixi_exec_path: Path = _which("pixi" + binary_ext) + package_env_config: dict[str, str | Path | None] = {} + + args.build_dir_root = Path(args.build_dir_root) + if str(args.build_dir_root) != str(default_build_dir_root) and str( + args.itk_source_dir + ) == str(default_itk_source_dir): + args.itk_source_dir = args.build_dir_root / "ITK" + + args.itk_source_dir = Path(args.itk_source_dir) + package_env_config["ITK_SOURCE_DIR"] = Path(args.itk_source_dir) + + ipp_superbuild_binary_dir: Path = args.build_dir_root / "build" / "ITK-support-bld" + package_env_config["IPP_SUPERBUILD_BINARY_DIR"] = ipp_superbuild_binary_dir + + package_env_config["OS_NAME"] = os_name + package_env_config["ARCH"] = arch + + # ITK repo handling + + if not Path(args.itk_source_dir).exists(): + args.itk_source_dir.parent.mkdir(parents=True, exist_ok=True) + print(f"Cloning ITK into {args.itk_source_dir}...") + run_result = run_commandLine_subprocess( + [ + "git", + "clone", + "https://github.com/InsightSoftwareConsortium/ITK.git", + str(args.itk_source_dir), + ], + cwd=_ipp_dir_path, + env=os.environ.copy(), + ) + if run_result.returncode != 0: + raise RuntimeError(f"Failed to clone ITK: {run_result.stderr}") + + run_commandLine_subprocess( + ["git", "fetch", "--tags", "origin"], + cwd=args.itk_source_dir, + env=os.environ.copy(), + ) + try: + run_commandLine_subprocess( + ["git", "checkout", args.itk_git_tag], + cwd=args.itk_source_dir, + env=os.environ.copy(), + ) + except subprocess.CalledProcessError: + print(f"WARNING: Failed to checkout {args.itk_git_tag}, reverting to 'main':") + run_commandLine_subprocess( + ["git", "checkout", "main"], + cwd=args.itk_source_dir, + env=os.environ.copy(), + ) + + if ( + args.itk_package_version == "auto" + or args.itk_package_version is None + or len(args.itk_package_version) == 0 + ): + args.itk_package_version = os.environ.get( + "ITK_PACKAGE_VERSION", + compute_itk_package_version( + args.itk_source_dir, args.itk_git_tag, pixi_exec_path, os.environ + ), + ) + + # ITKPythonPackage origin/tag + # NO_SUDO, ITK_MODULE_NO_CLEANUP, USE_CCACHE + no_sudo = os.environ.get("NO_SUDO", "0") + module_no_cleanup = os.environ.get("ITK_MODULE_NO_CLEANUP", "1") + use_ccache = os.environ.get("USE_CCACHE", "0") + + package_env_config["BUILD_DIR_ROOT"] = str(args.build_dir_root) + package_env_config["ITK_GIT_TAG"] = args.itk_git_tag + package_env_config["ITK_SOURCE_DIR"] = args.itk_source_dir + package_env_config["ITK_PACKAGE_VERSION"] = args.itk_package_version + if os_name == "darwin": + package_env_config["MACOSX_DEPLOYMENT_TARGET"] = args.macosx_deployment_target + else: + package_env_config["MACOSX_DEPLOYMENT_TARGET"] = "RELEVANT_FOR_MACOS_ONLY" + package_env_config["ITK_MODULE_PREQ"] = args.itk_module_deps + package_env_config["NO_SUDO"] = no_sudo + package_env_config["ITK_MODULE_NO_CLEANUP"] = module_no_cleanup + package_env_config["USE_CCACHE"] = use_ccache + package_env_config["PIXI_EXECUTABLE"] = _which("pixi") + package_env_config["CMAKE_EXECUTABLE"] = _which("cmake") + package_env_config["NINJA_EXECUTABLE"] = _which("ninja") + package_env_config["DOXYGEN_EXECUTABLE"] = _which("doxygen") + package_env_config["GIT_EXECUTABLE"] = _which("git") + + # reliably find the python executable in pixi + cmd = [ + package_env_config["PIXI_EXECUTABLE"], + "run", + "-e", + args.platform_env, + "python", + "-c", + "import sys; print(sys.executable)", + ] + package_env_config["PYTHON_EXECUTABLE"] = run_commandLine_subprocess( + cmd, env=os.environ.copy() + ).stdout.strip() + + oci_exe = resolve_oci_exe(os.environ.copy()) + package_env_config["OCI_EXE"] = oci_exe + del oci_exe + + # ------------- + platform = package_env_config["OS_NAME"].lower() + if platform == "windows": + from windows_build_python_instance import WindowsBuildPythonInstance + + builder_cls = WindowsBuildPythonInstance + elif platform in ("darwin", "mac", "macos", "macosx", "osx"): + from macos_build_python_instance import MacOSBuildPythonInstance + + builder_cls = MacOSBuildPythonInstance + elif platform == "linux": + from linux_build_python_instance import LinuxBuildPythonInstance + + # Manylinux/docker bits for Linux + target_arch = os.environ.get("TARGET_ARCH") or arch + + manylinux_version: str = args.manylinux_version + if manylinux_version and len(manylinux_version) > 0: + if ( + os.environ.get("MANYLINUX_VERSION", manylinux_version) + != manylinux_version + ): + print( + f"WARNING: environment variable MANYLINUX_VERSION={manylinux_version} is changed to command line value of {manylinux_version}." + ) + package_env_config["MANYLINUX_VERSION"] = manylinux_version + image_tag, manylinux_image_name, container_source = default_manylinux( + manylinux_version, os_name, target_arch, os.environ.copy() + ) + package_env_config["IMAGE_TAG"] = image_tag + package_env_config["MANYLINUX_IMAGE_NAME"] = manylinux_image_name + package_env_config["CONTAINER_SOURCE"] = container_source + package_env_config["TARGET_ARCH"] = target_arch + + # Native builds without dockcross need a separate dist dir to avoid conflicts with manylinux + # dist_dir = IPP_SOURCE_DIR / f"{platform}_dist" + # For the aarch64 manylinux builds, the CROSS_TRIPLE environment variable is unset + if os.environ.get("CROSS_TRIPLE", None) is None and target_arch not in ( + "arm64", + "aarch64", + ): + msg: str = ( + f"ERROR: MANYLINUX_VERSION={manylinux_version} and TARGET_ARCH={target_arch} but not building in dockcross." + ) + raise RuntimeError(msg) + + builder_cls = LinuxBuildPythonInstance + else: + raise ValueError(f"Unknown platform {platform}") + + print("=" * 80) + print("=" * 80) + print("= Building Wheels with effective command line") + print("\n\n") + cmdline: str = f"{get_effective_command_line(parser, args)}" + args.build_dir_root.mkdir(parents=True, exist_ok=True) + with open( + args.build_dir_root / f"effective_cmdline_{args.platform_env}.sh", "w" + ) as f: + f.write("#!/bin/bash\n") + f.write( + "# Generated by build_wheels.py as documentation for describing how these wheels were created.\n" + ) + f.write(cmdline) + f.write("\n") + print(f"cmdline: {cmdline}") + print("\n\n\n\n") + print("=" * 80) + print("=" * 80) + print(f"Building wheels for platform: {args.platform_env}") + # Pass helper function callables and dist dir to avoid circular imports + builder = builder_cls( + platform_env=args.platform_env, + build_dir_root=args.build_dir_root, + package_env_config=package_env_config, + cleanup=args.cleanup, + build_itk_tarball_cache=args.build_itk_tarball_cache, + cmake_options=args.cmake_options, + windows_extra_lib_paths=args.lib_paths, + dist_dir=dist_dir, + module_source_dir=args.module_source_dir, + module_dependencies_root_dir=args.module_dependencies_root_dir, + itk_module_deps=args.itk_module_deps, + skip_itk_build=args.skip_itk_build, + skip_itk_wheel_build=args.skip_itk_wheel_build, + ) + builder.run() + + +if __name__ == "__main__": + build_wheels_main() diff --git a/scripts/cmake_argument_builder.py b/scripts/cmake_argument_builder.py new file mode 100644 index 00000000..22aee6d2 --- /dev/null +++ b/scripts/cmake_argument_builder.py @@ -0,0 +1,107 @@ +from collections.abc import Iterable, Iterator, Mapping + + +def drop_quotes(s: str) -> str: + """Strip surrounding double-quote characters from *s*.""" + return str(s).strip('"') + + +class CMakeArgumentBuilder: + """Manage CMake-style key/value definitions and render them as CLI args. + + Keys should include any CMake type suffix (e.g. + ``'CMAKE_BUILD_TYPE:STRING'``). Values are rendered verbatim. + + Parameters + ---------- + initial : Mapping[str, str], optional + Initial set of definitions to populate the builder. + + Examples + -------- + >>> flags = { + ... 'CMAKE_BUILD_TYPE:STRING': 'Release', + ... 'CMAKE_OSX_ARCHITECTURES:STRING': 'arm64', + ... } + >>> builder = CMakeArgumentBuilder(flags) + >>> builder.getCMakeCommandLineArguments() + ["-DCMAKE_BUILD_TYPE:STRING='Release'", "-DCMAKE_OSX_ARCHITECTURES:STRING='arm64'"] + >>> builder.getPythonBuildCommandLineArguments() + ['--config-setting=cmake.define.CMAKE_BUILD_TYPE:STRING=Release', + '--config-setting=cmake.define.CMAKE_OSX_ARCHITECTURES:STRING=arm64'] + """ + + def __init__(self, initial: Mapping[str, str] | None = None) -> None: + # dict preserves insertion order; keep user's order when possible + self._defs: dict[str, str] = dict(initial) if initial else {} + + # Basic mapping helpers (optional convenience) + def set(self, key: str, value: str) -> None: + """Set or replace a definition. + + Parameters + ---------- + key : str + CMake variable name, optionally with a type suffix + (e.g. ``'CMAKE_BUILD_TYPE:STRING'``). + value : str + Value for the definition. + """ + self._defs[key] = value + + def get(self, key: str, default: str | None = None) -> str | None: + """Return the value for *key*, or *default* if absent.""" + return self._defs.get(key, default) + + def update(self, other: Mapping[str, str] | Iterable[tuple[str, str]]) -> None: + """Merge definitions from *other* into this builder. + + Parameters + ---------- + other : Mapping[str, str] or Iterable[tuple[str, str]] + Definitions to merge. Existing keys are overwritten. + """ + if isinstance(other, Mapping): + self._defs.update(other) + else: + for k, v in other: + self._defs[k] = v + + def __contains__(self, key: str) -> bool: # pragma: no cover - trivial + return key in self._defs + + def __getitem__(self, key: str) -> str: # pragma: no cover - trivial + return self._defs[key] + + def __iter__(self) -> Iterator[str]: # pragma: no cover - trivial + return iter(self._defs) + + def items(self) -> Iterable[tuple[str, str]]: # pragma: no cover - trivial + """Return an iterable of ``(key, value)`` definition pairs.""" + return self._defs.items() + + # Renderers + def getCMakeCommandLineArguments(self) -> list[str]: + """Render definitions as CMake ``-D`` arguments. + + Returns + ------- + list[str] + A list like ``["-D=''", ...]``. + """ + return [f"""-D{k}='{drop_quotes(v)}'""" for k, v in self._defs.items()] + + def getPythonBuildCommandLineArguments(self) -> list[str]: + """Render definitions as scikit-build-core ``--config-setting`` arguments. + + Returns + ------- + list[str] + A list like + ``["--config-setting=cmake.define.=''", ...]``. + """ + prefix = "--config-setting=cmake.define." + return [f"""{prefix}{k}='{drop_quotes(v)}'""" for k, v in self._defs.items()] + + +__all__ = ["CMakeArgumentBuilder"] diff --git a/scripts/dockcross-manylinux-build-module-deps.sh b/scripts/dockcross-manylinux-build-module-deps.sh deleted file mode 100755 index dede51d3..00000000 --- a/scripts/dockcross-manylinux-build-module-deps.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/bin/bash - -######################################################################## -# Run this script in an ITK external module directory to generate -# build artifacts for prerequisite ITK external modules. -# -# Module dependencies are built in a flat directory structure regardless -# of recursive dependencies. Prerequisite sources are required to be passed -# in the order in which they should be built. -# For example, if ITKTargetModule depends on ITKTargetModuleDep2 which -# depends on ITKTargetModuleDep1, the output directory structure -# will look like this: -# -# / ITKTargetModule -# -- / ITKTargetModuleDep1 -# -- / ITKTargetModuleDep2 -# .. -# -# =========================================== -# ENVIRONMENT VARIABLES -# -# - `ITK_MODULE_PREQ`: Prerequisite ITK modules that must be built before the requested module. -# Format is `/@:/@:...`. -# For instance, `export ITK_MODULE_PREQ=InsightSoftwareConsortium/ITKMeshToPolyData@v0.10.0` -# -######################################################################## - -# Initialize variables - -script_dir=$(cd $(dirname $0) || exit 1; pwd) -if [[ ! -f "${script_dir}/dockcross-manylinux-download-cache-and-build-module-wheels.sh" ]]; then - echo "Could not find download script to use for building module dependencies!" - exit 1 -fi - -source "${script_dir}/dockcross-manylinux-set-vars.sh" - -# Temporarily update prerequisite environment variable to prevent infinite recursion. -ITK_MODULE_PREQ_TOPLEVEL=${ITK_MODULE_PREQ} -ITK_MODULE_NO_CLEANUP_TOPLEVEL=${ITK_MODULE_NO_CLEANUP} -export ITK_MODULE_PREQ="" -export ITK_MODULE_NO_CLEANUP="ON" - -######################################################################## -# Build ITK module dependencies - -for MODULE_INFO in ${ITK_MODULE_PREQ_TOPLEVEL//:/ }; do - MODULE_ORG=`(echo ${MODULE_INFO} | cut -d'/' -f 1)` - MODULE_NAME=`(echo ${MODULE_INFO} | cut -d'@' -f 1 | cut -d'/' -f 2)` - MODULE_TAG=`(echo ${MODULE_INFO} | cut -d'@' -f 2)` - - MODULE_UPSTREAM=https://github.com/${MODULE_ORG}/${MODULE_NAME}.git - echo "Cloning from ${MODULE_UPSTREAM}" - git clone ${MODULE_UPSTREAM} - - # Reuse cached build archive instead of redownloading. - # Build archives are usually ~2GB so it is reasonable to move - # instead of redownloading. - if [[ `(compgen -G ./ITKPythonBuilds-linux*.tar.zst)` ]]; then - mv ITKPythonBuilds-linux*.tar.zst ${MODULE_NAME}/ - fi - - pushd ${MODULE_NAME} - git checkout ${MODULE_TAG} - cp ../dockcross-manylinux-download-cache-and-build-module-wheels.sh . - if [[ -d ../ITKPythonPackage ]]; then - ln -s ../ITKPythonPackage - ln -s ./ITKPythonPackage/oneTBB-prefix - fi - - echo "Building module dependency ${MODULE_NAME}" - ./dockcross-manylinux-download-cache-and-build-module-wheels.sh "$@" - popd - - echo "Cleaning up module dependency" - cp ./${MODULE_NAME}/include/* include/ - find ${MODULE_NAME}/wrapping -name '*.in' -print -exec cp {} wrapping \; - find ${MODULE_NAME}/wrapping -name '*.init' -print -exec cp {} wrapping \; - find ${MODULE_NAME}/*build/*/include -type f -print -exec cp {} include \; - - # Cache build archive - if [[ `(compgen -G ./ITKPythonBuilds-linux*.tar.zst)` ]]; then - rm -f ./${MODULE_NAME}/ITKPythonBuilds-linux*.tar.zst - else - mv ./${MODULE_NAME}/ITKPythonBuilds-linux*.tar.zst . - fi - - # Cache ITKPythonPackage build scripts - if [[ ! -d ./ITKPythonPackage ]]; then - mv ./${MODULE_NAME}/ITKPythonPackage . - ln -s ./ITKPythonPackage/oneTBB-prefix . - fi - -done - -# Restore environment variable -export ITK_MODULE_PREQ=${ITK_MODULE_PREQ_TOPLEVEL} -ITK_MODULE_PREQ_TOPLEVEL="" -export ITK_MODULE_NO_CLEANUP=${ITK_MODULE_NO_CLEANUP_TOPLEVEL} -ITK_MODULE_NO_CLEANUP_TOPLEVEL="" - -# Summarize disk usage for debugging -du -sh ./* | sort -hr | head -n 20 - -echo "Done building ITK external module dependencies" diff --git a/scripts/dockcross-manylinux-build-module-wheels.sh b/scripts/dockcross-manylinux-build-module-wheels.sh index 392a2190..4c6f04e4 100755 --- a/scripts/dockcross-manylinux-build-module-wheels.sh +++ b/scripts/dockcross-manylinux-build-module-wheels.sh @@ -4,9 +4,6 @@ # Run this script to build the Python wheel packages for Linux for an ITK # external module. # -# ======================================================================== -# PARAMETERS -# # Versions can be restricted by passing them in as arguments to the script # For example, # @@ -26,13 +23,13 @@ # # `MANYLINUX_VERSION`: Specialized manylinux image to use for building. Default is _2_28. # See https://github.com/dockcross/dockcross for available versions and tags. -# For instance, `export MANYLINUX_VERSION=2014` +# For instance, `export MANYLINUX_VERSION=_2_28` # # `TARGET_ARCH`: Target architecture for which wheels should be built. # For instance, `export MANYLINUX_VERSION=aarch64` # # `IMAGE_TAG`: Specialized manylinux image tag to use for building. -# For instance, `export IMAGE_TAG=20221205-459c9f0`. +# For instance, `export IMAGE_TAG=2025.08.12-1`. # Tagged images are available at: # - https://github.com/dockcross/dockcross (x64 architecture) # - https://quay.io/organization/pypa (ARM architecture) @@ -44,62 +41,179 @@ # # - `NO_SUDO`: Disable the use of superuser permissions for running docker. # +# DIRECTORY STRUCTURE (expected): +# ${IPP_DIR}/ <- ITKPythonPackage +# ${BUILD_DIR}/ <- ITKPythonPackage-manylinux${VERSION}-build +# ${MODULE_SOURCE_DIR}/ <- Module source (current directory) ######################################################################## -# Handle case where the script directory is not the working directory -script_dir=$(cd $(dirname $0) || exit 1; pwd) -source "${script_dir}/dockcross-manylinux-set-vars.sh" -source "${script_dir}/oci_exe.sh" +script_dir=$( + cd "$(dirname "$0")" || exit 1 + pwd +) +_ipp_dir=$(dirname "${script_dir}") + +# ----------------------------------------------------------------------- +# Find container runtime +for cand in nerdctl docker podman; do + if which "${cand}" >/dev/null 2>&1; then + export OCI_EXE=${OCI_EXE:-"$cand"} + break + fi +done -oci_exe=$(ociExe) +if [ -z "${OCI_EXE}" ]; then + echo "ERROR: No container runtime found. Please install docker, podman, or nerdctl." + exit 1 +fi +echo "Found OCI_EXE=$(which "${OCI_EXE}")" -if [[ -n ${ITK_MODULE_PREQ} ]]; then - echo "Building module dependencies ${ITK_MODULE_PREQ}" - source "${script_dir}/dockcross-manylinux-build-module-deps.sh" +# ----------------------------------------------------------------------- +# Set default values +MANYLINUX_VERSION=${MANYLINUX_VERSION:-_2_28} +TARGET_ARCH=${TARGET_ARCH:-x64} +# Default image tag differs by architecture: +# x64 → dockcross/manylinux image (docker.io/dockcross) +# aarch64 → pypa manylinux image (quay.io/pypa, native ARM64 / QEMU on x64) +if [[ "${TARGET_ARCH}" == "aarch64" ]]; then + IMAGE_TAG=${IMAGE_TAG:-2025.08.12-1} + CONTAINER_SOURCE=${CONTAINER_SOURCE:-"quay.io/pypa/manylinux${MANYLINUX_VERSION}_${TARGET_ARCH}:${IMAGE_TAG}"} +else + # if x64 arch then default manylinux version is _2_28 + IMAGE_TAG=${IMAGE_TAG:=20260203-3dfb3ff} + CONTAINER_SOURCE=${CONTAINER_SOURCE:-"docker.io/dockcross/manylinux${MANYLINUX_VERSION}-${TARGET_ARCH}:${IMAGE_TAG}"} fi +ITKPYTHONPACKAGE_ORG=${ITKPYTHONPACKAGE_ORG:-InsightSoftwareConsortium} +ITKPYTHONPACKAGE_TAG=${ITKPYTHONPACKAGE_TAG:-main} + +# For backwards compatibility +ITK_GIT_TAG=${ITK_GIT_TAG:-${ITK_PACKAGE_VERSION}} + +# Required environment variables +required_vars=( + ITK_GIT_TAG + MANYLINUX_VERSION + IMAGE_TAG + TARGET_ARCH + ITKPYTHONPACKAGE_ORG + ITKPYTHONPACKAGE_TAG +) +# Sanity Validation loop +_missing_required=0 +for v in "${required_vars[@]}"; do + if [ -z "${!v:-}" ]; then + _missing_required=1 + echo "ERROR: Required environment variable '$v' is not set or empty." + fi +done +if [ "${_missing_required}" -ne 0 ]; then + exit 1 +fi +unset _missing_required + +mkdir -p "${_ipp_dir}"/build +cd "$(dirname "${_ipp_dir}")" || exit + +HOST_MODULE_DIRECTORY=${MODULE_SRC_DIRECTORY} # Set up paths and variables for build -mkdir -p $(pwd)/tools -chmod 777 $(pwd)/tools -mkdir -p dist -DOCKER_ARGS="-v $(pwd)/dist:/work/dist/ -v ${script_dir}/..:/ITKPythonPackage -v $(pwd)/tools:/tools" -DOCKER_ARGS+=" -e MANYLINUX_VERSION" -DOCKER_ARGS+=" -e LD_LIBRARY_PATH" -# Mount any shared libraries +CONTAINER_WORK_DIR=/work +CONTAINER_PACKAGE_BUILD_DIR=${CONTAINER_WORK_DIR}/ITKPythonPackage-build +CONTAINER_PACKAGE_SCRIPTS_DIR=${CONTAINER_WORK_DIR}/ITKPythonPackage +HOST_PACKAGE_BUILD_DIR=$(dirname "${_ipp_dir}")/ITKPythonPackage-build +HOST_PACKAGE_SCRIPTS_DIR=${_ipp_dir} + +CONTAINER_ITK_SOURCE_DIR=${CONTAINER_PACKAGE_BUILD_DIR}/ITK +HOST_PACKAGE_DIST=${HOST_MODULE_DIRECTORY}/dist +mkdir -p "${HOST_PACKAGE_DIST}" +CONTAINER_MODULE_DIR=${CONTAINER_WORK_DIR}/$(basename "${MODULE_SRC_DIRECTORY}") +CONTAINER_MODULE_DEPS_DIR=${CONTAINER_WORK_DIR}/$(basename "${MODULE_DEPS_DIR}") + +# Build docker arguments +DOCKER_ARGS=" --network=host " +DOCKER_ARGS+=" -v ${HOST_PACKAGE_BUILD_DIR}:${CONTAINER_PACKAGE_BUILD_DIR} " +DOCKER_ARGS+=" -v ${HOST_PACKAGE_SCRIPTS_DIR}:${CONTAINER_PACKAGE_SCRIPTS_DIR} " +DOCKER_ARGS+=" -v ${MODULE_SRC_DIRECTORY}:${CONTAINER_MODULE_DIR} " +DOCKER_ARGS+=" -v ${MODULE_DEPS_DIR}:${CONTAINER_MODULE_DEPS_DIR} " + +if [ "${ITK_SOURCE_DIR}" != "" ]; then + DOCKER_ARGS+=" -v ${ITK_SOURCE_DIR}:${CONTAINER_ITK_SOURCE_DIR} " +fi + +# Environment variables for the container +DOCKER_ARGS+=" -e PYTHONUNBUFFERED=1 " +DOCKER_ARGS+=" -e CMAKE_OPTIONS='${CMAKE_OPTIONS}' " + +# Mount shared libraries if LD_LIBRARY_PATH is set if [[ -n ${LD_LIBRARY_PATH} ]]; then for libpath in ${LD_LIBRARY_PATH//:/ }; do - DOCKER_LIBRARY_PATH="/usr/lib64/$(basename -- ${libpath})" - DOCKER_ARGS+=" -v ${libpath}:${DOCKER_LIBRARY_PATH}" - if test -d ${libpath}; then - DOCKER_LD_LIBRARY_PATH+="${DOCKER_LIBRARY_PATH}:${DOCKER_LD_LIBRARY_PATH}" - fi + DOCKER_LIBRARY_PATH="/usr/lib64/$(basename -- "${libpath}")" + DOCKER_ARGS+=" -v ${libpath}:${DOCKER_LIBRARY_PATH}" + if test -d "${libpath}"; then + DOCKER_LD_LIBRARY_PATH+="${DOCKER_LIBRARY_PATH}:${DOCKER_LD_LIBRARY_PATH}" + fi done fi export LD_LIBRARY_PATH="${DOCKER_LD_LIBRARY_PATH}" -if [[ "${TARGET_ARCH}" = "aarch64" ]]; then - echo "Install aarch64 architecture emulation tools to perform build for ARM platform" +# To build tarballs in manylinux, use 'export BUILD_WHEELS_EXTRA_FLAGS=" --build-itk-tarball-cache "' +BUILD_WHEELS_EXTRA_FLAGS=${BUILD_WHEELS_EXTRA_FLAGS:=""} # No tarball by default +PY_ENVS=("${@:-py310 py311}") + +if [[ "${TARGET_ARCH}" == "aarch64" ]]; then + # aarch64: run the quay.io/pypa native image directly. + # On ARM64 hosts (e.g. Apple Silicon) this runs natively. + # On x64 hosts, first register QEMU binfmt emulation. if [[ ! ${NO_SUDO} ]]; then docker_prefix="sudo" fi + # Only install QEMU binfmt emulation on non-ARM64 hosts; ARM64 hosts run natively + if [[ "$(uname -m)" != "arm64" && "$(uname -m)" != "aarch64" ]]; then + echo "Installing aarch64 architecture emulation tools to perform build for ARM platform" + ${docker_prefix} "$OCI_EXE" run --privileged --rm tonistiigi/binfmt --install all + fi - ${docker_prefix} $oci_exe run --privileged --rm tonistiigi/binfmt --install all - - # Build wheels - DOCKER_ARGS+=" -v $(pwd):/work/ --rm" - ${docker_prefix} $oci_exe run $DOCKER_ARGS ${CONTAINER_SOURCE} "/ITKPythonPackage/scripts/internal/manylinux-aarch64-build-module-wheels.sh" "$@" + cmd="${docker_prefix} \"$OCI_EXE\" run --rm \ + ${DOCKER_ARGS} \ + -e PY_ENVS=\"${PY_ENVS[*]}\" \ + -e ITK_GIT_TAG=\"${ITK_GIT_TAG}\" \ + -e ITK_PACKAGE_VERSION=\"${ITK_PACKAGE_VERSION}\" \ + -e ITK_MODULE_PREQ=\"${ITK_MODULE_PREQ}\" \ + -e MODULE_SRC_DIRECTORY=\"${CONTAINER_MODULE_DIR}\" \ + -e MODULE_DEPS_DIR=\"${CONTAINER_MODULE_DEPS_DIR}\" \ + -e MANYLINUX_VERSION=\"${MANYLINUX_VERSION}\" \ + -e IMAGE_TAG=\"${IMAGE_TAG}\" \ + -e TARGET_ARCH=\"${TARGET_ARCH}\" \ + -e ITKPYTHONPACKAGE_ORG=\"${ITKPYTHONPACKAGE_ORG}\" \ + -e ITKPYTHONPACKAGE_TAG=\"${ITKPYTHONPACKAGE_TAG}\" \ + -e BUILD_WHEELS_EXTRA_FLAGS=\"${BUILD_WHEELS_EXTRA_FLAGS}\" \ + ${CONTAINER_SOURCE} \ + /bin/bash -x ${CONTAINER_PACKAGE_SCRIPTS_DIR}/scripts/docker_build_environment_driver.sh" else - # Generate dockcross scripts - $oci_exe run --rm ${CONTAINER_SOURCE} > /tmp/dockcross-manylinux-x64 - chmod u+x /tmp/dockcross-manylinux-x64 - - # Build wheels - /tmp/dockcross-manylinux-x64 \ - -a "$DOCKER_ARGS" \ - "/ITKPythonPackage/scripts/internal/manylinux-build-module-wheels.sh" "$@" -fi + # x64: generate the dockcross runner script from the image, then invoke it. + _local_dockcross_script=${_ipp_dir}/build/runner_dockcross-${MANYLINUX_VERSION}-${TARGET_ARCH}_${IMAGE_TAG}.sh + "$OCI_EXE" run --rm "${CONTAINER_SOURCE}" >"${_local_dockcross_script}" + chmod u+x "${_local_dockcross_script}" -if [[ -z ${ITK_MODULE_NO_CLEANUP} ]]; then - source "${script_dir}/dockcross-manylinux-cleanup.sh" + # When building ITK remote wheels, --module-source-dir, --module-dependencies-root-dir, and --itk-module-deps should be present + cmd="bash -x ${_local_dockcross_script} \ + -a \"$DOCKER_ARGS\" \ + /usr/bin/env \ + PY_ENVS=\"${PY_ENVS[*]}\" \ + ITK_GIT_TAG=\"${ITK_GIT_TAG}\" \ + ITK_PACKAGE_VERSION=\"${ITK_PACKAGE_VERSION}\" \ + ITK_MODULE_PREQ=\"${ITK_MODULE_PREQ}\" \ + MODULE_SRC_DIRECTORY=\"${CONTAINER_MODULE_DIR}\" \ + MODULE_DEPS_DIR=\"${CONTAINER_MODULE_DEPS_DIR}\" \ + MANYLINUX_VERSION=\"${MANYLINUX_VERSION}\" \ + IMAGE_TAG=\"${IMAGE_TAG}\" \ + TARGET_ARCH=\"${TARGET_ARCH}\" \ + ITKPYTHONPACKAGE_ORG=\"${ITKPYTHONPACKAGE_ORG}\" \ + ITKPYTHONPACKAGE_TAG=\"${ITKPYTHONPACKAGE_TAG}\" \ + BUILD_WHEELS_EXTRA_FLAGS=\"${BUILD_WHEELS_EXTRA_FLAGS}\" \ + /bin/bash -x ${CONTAINER_PACKAGE_SCRIPTS_DIR}/scripts/docker_build_environment_driver.sh" fi + +echo "RUNNING: $cmd" +eval "$cmd" diff --git a/scripts/dockcross-manylinux-build-tarball.sh b/scripts/dockcross-manylinux-build-tarball.sh deleted file mode 100755 index ca29e75c..00000000 --- a/scripts/dockcross-manylinux-build-tarball.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash - -# This script creates a tarball of the ITK Python package build tree. It is -# downloaded by the external module build scripts and used to build their -# Python package on GitHub CI services. - -# ----------------------------------------------------------------------- - -zstd_exe=`(which zstd)` - -# Find an appropriately versioned zstd. -# -# "--long" is introduced in zstd==v1.3.2 -# https://github.com/facebook/zstd/releases/tag/v1.3.2 -# -# Sample --version output: -# *** zstd command line interface 64-bits v1.4.4, by Yann Collet *** # -ZSTD_MIN_VERSION="1.3.2" - -if [[ -n `(which dpkg)` && `(${zstd_exe} --version)` =~ v([0-9]+.[0-9]+.[0-9]+) ]]; then - if $(dpkg --compare-versions ${BASH_REMATCH[1]} "ge" ${ZSTD_MIN_VERSION} ); then - echo "Found zstd v${BASH_REMATCH[1]} at ${zstd_exe}" - else - echo "Expected zstd v${ZSTD_MIN_VERSION} or higher but found v${BASH_REMATCH[1]} at ${zstd_exe}" - exit 255 - fi -else - # dpkg not available for version comparison so simply print version - ${zstd_exe} --version -fi - -# ----------------------------------------------------------------------- - -tar -cf ITKPythonBuilds-linux.tar \ - ITKPythonPackage/ITK-* \ - ITKPythonPackage/oneTBB* \ - ITKPythonPackage/requirements-dev.txt \ - ITKPythonPackage/scripts -$zstd_exe -f \ - -10 \ - -T6 \ - --long=31 \ - ./ITKPythonBuilds-linux.tar \ - -o ./ITKPythonBuilds-linux.tar.zst diff --git a/scripts/dockcross-manylinux-build-wheels.sh b/scripts/dockcross-manylinux-build-wheels.sh index 0619b301..eadba903 100755 --- a/scripts/dockcross-manylinux-build-wheels.sh +++ b/scripts/dockcross-manylinux-build-wheels.sh @@ -1,5 +1,4 @@ #!/bin/bash - # Run this script to build the ITK Python wheel packages for Linux. # # Versions can be restricted by passing them in as arguments to the script @@ -7,42 +6,144 @@ # # scripts/dockcross-manylinux-build-wheels.sh cp310 # -# A specialized manylinux image and tag can be used by exporting to -# MANYLINUX_VERSION and IMAGE_TAG before running this script. -# See https://github.com/dockcross/dockcross for available versions and tags. +# A specialized manylinux image and tag can be used by setting +# MANYLINUX_VERSION and IMAGE_TAG # # For example, # -# export MANYLINUX_VERSION=2014 -# export IMAGE_TAG=20221205-459c9f0 +# export MANYLINUX_VERSION=_2_28 +# export IMAGE_TAG=20260203-3dfb3ff # scripts/dockcross-manylinux-build-module-wheels.sh cp310 # -script_dir=$(cd $(dirname $0) || exit 1; pwd) -source "${script_dir}/oci_exe.sh" +script_dir=$( + cd "$(dirname "$0")" || exit 1 + pwd +) +_ipp_dir=$(dirname "${script_dir}") -oci_exe=$(ociExe) +for cand in nerdctl docker podman; do + if which "${cand}" >/dev/null; then + export OCI_EXE=${OCI_EXE:="$cand"} + break + fi +done +echo "FOUND OCI_EXE=$(which "${OCI_EXE}")" +#For backwards compatibility when the ITK_GIT_TAG was required to match the ITK_PACKAGE_VERSION +ITK_PACKAGE_VERSION=${ITK_PACKAGE_VERSION:="v6.0b02"} +ITK_GIT_TAG=${ITK_GIT_TAG:=${ITK_PACKAGE_VERSION}} MANYLINUX_VERSION=${MANYLINUX_VERSION:=_2_28} -if [[ ${MANYLINUX_VERSION} == _2_28 ]]; then +# Default image tag differs by architecture: +# x64 → dockcross/manylinux image (docker.io/dockcross) +# aarch64 → pypa manylinux image (quay.io/pypa, native ARM64 / QEMU on x64) +if [[ "${TARGET_ARCH}" == "aarch64" ]]; then + IMAGE_TAG=${IMAGE_TAG:=2025.08.12-1} + CONTAINER_SOURCE=${CONTAINER_SOURCE:="quay.io/pypa/manylinux${MANYLINUX_VERSION}_${TARGET_ARCH}:${IMAGE_TAG}"} +else + # if x64 arch then default manylinux version is _2_28 IMAGE_TAG=${IMAGE_TAG:=20260203-3dfb3ff} -elif [[ ${MANYLINUX_VERSION} == 2014 ]]; then - IMAGE_TAG=${IMAGE_TAG:=20240304-9e57d2b} + CONTAINER_SOURCE=${CONTAINER_SOURCE:="docker.io/dockcross/manylinux${MANYLINUX_VERSION}-${TARGET_ARCH}:${IMAGE_TAG}"} +fi +ITKPYTHONPACKAGE_ORG=${ITKPYTHONPACKAGE_ORG:=InsightSoftwareConsortium} +ITKPYTHONPACKAGE_TAG=${ITKPYTHONPACKAGE_TAG:=main} + +# Required environment variables +required_vars=( + ITK_GIT_TAG + MANYLINUX_VERSION + IMAGE_TAG + TARGET_ARCH + ITKPYTHONPACKAGE_ORG + ITKPYTHONPACKAGE_TAG +) +# Sanity Validation loop +_missing_required=0 +for v in "${required_vars[@]}"; do + if [ -z "${!v:-}" ]; then + _missing_required=1 + echo "ERROR: Required environment variable '$v' is not set or empty." + fi +done +if [ "${_missing_required}" -ne 0 ]; then + exit 1 +fi +unset _missing_required + +mkdir -p "${_ipp_dir}/build" +cd "$(dirname "${_ipp_dir}")" || exit + +# Build wheels in dockcross environment +CONTAINER_WORK_DIR=/work +CONTAINER_PACKAGE_BUILD_DIR=${CONTAINER_WORK_DIR}/ITKPythonPackage-build +CONTAINER_PACKAGE_SCRIPTS_DIR=${CONTAINER_WORK_DIR}/ITKPythonPackage +CONTAINER_ITK_SOURCE_DIR=${CONTAINER_PACKAGE_BUILD_DIR}/ITK + +HOST_PACKAGE_SCRIPTS_DIR=${_ipp_dir} +HOST_PACKAGE_BUILD_DIR=$(dirname "${_ipp_dir}")/ITKPythonPackage-manylinux${MANYLINUX_VERSION}-build +mkdir -p "${HOST_PACKAGE_BUILD_DIR}" + +DOCKER_ARGS=" -v ${HOST_PACKAGE_BUILD_DIR}:${CONTAINER_PACKAGE_BUILD_DIR} " +DOCKER_ARGS+=" -v ${HOST_PACKAGE_SCRIPTS_DIR}:${CONTAINER_PACKAGE_SCRIPTS_DIR} " +if [ "${ITK_SOURCE_DIR}" != "" ]; then + DOCKER_ARGS+=" -v${ITK_SOURCE_DIR}:${CONTAINER_ITK_SOURCE_DIR} " +fi +DOCKER_ARGS+=" -e PYTHONUNBUFFERED=1 " # Turn off buffering of outputs in python + +# To build tarballs in manylinux, use 'export BUILD_WHEELS_EXTRA_FLAGS=" --build-itk-tarball-cache "' +BUILD_WHEELS_EXTRA_FLAGS=${BUILD_WHEELS_EXTRA_FLAGS:=""} # No tarball by default + +# If args are given, use them. Otherwise use default python environments +PY_ENVS=("${@:-py310 py311}") + +if [[ "${TARGET_ARCH}" == "aarch64" ]]; then + # aarch64: run the quay.io/pypa native image directly. + # On ARM64 hosts (e.g. Apple Silicon) this runs natively. + # On x64 hosts, first register QEMU binfmt emulation. + if [[ ! ${NO_SUDO} ]]; then + docker_prefix="sudo" + fi + # Only install QEMU binfmt emulation on non-ARM64 hosts; ARM64 hosts run natively + if [[ "$(uname -m)" != "arm64" && "$(uname -m)" != "aarch64" ]]; then + echo "Installing aarch64 architecture emulation tools to perform build for ARM platform" + ${docker_prefix} "$OCI_EXE" run --privileged --rm tonistiigi/binfmt --install all + fi + + # When building ITK wheels, module-related vars are empty + cmd="${docker_prefix} \"$OCI_EXE\" run --rm \ + ${DOCKER_ARGS} \ + -e PY_ENVS=\"${PY_ENVS[*]}\" \ + -e ITK_GIT_TAG=\"${ITK_GIT_TAG}\" \ + -e ITK_PACKAGE_VERSION=\"${ITK_PACKAGE_VERSION:-}\" \ + -e MANYLINUX_VERSION=\"${MANYLINUX_VERSION}\" \ + -e IMAGE_TAG=\"${IMAGE_TAG}\" \ + -e TARGET_ARCH=\"${TARGET_ARCH}\" \ + -e ITKPYTHONPACKAGE_ORG=\"${ITKPYTHONPACKAGE_ORG}\" \ + -e ITKPYTHONPACKAGE_TAG=\"${ITKPYTHONPACKAGE_TAG}\" \ + -e BUILD_WHEELS_EXTRA_FLAGS=\"${BUILD_WHEELS_EXTRA_FLAGS}\" \ + ${CONTAINER_SOURCE} \ + /bin/bash -x ${CONTAINER_PACKAGE_SCRIPTS_DIR}/scripts/docker_build_environment_driver.sh" else - echo "Unknown manylinux version ${MANYLINUX_VERSION}" - exit 1; + # x64: generate the dockcross runner script from the image, then invoke it. + _local_dockercross_script=${_ipp_dir}/build/runner_dockcross-${MANYLINUX_VERSION}-${TARGET_ARCH}_${IMAGE_TAG}.sh + "$OCI_EXE" run --rm "${CONTAINER_SOURCE}" >"${_local_dockercross_script}" + chmod u+x "${_local_dockercross_script}" + + # When building ITK wheels, --module-source-dir, --module-dependancies-root-dir, and --itk-module-deps to be empty + cmd="bash -x ${_local_dockercross_script} \ + -a \"$DOCKER_ARGS\" \ + /usr/bin/env \ + PY_ENVS=\"${PY_ENVS[*]}\" \ + ITK_GIT_TAG=\"${ITK_GIT_TAG}\" \ + ITK_PACKAGE_VERSION=\"${ITK_PACKAGE_VERSION:-}\" \ + MANYLINUX_VERSION=\"${MANYLINUX_VERSION}\" \ + IMAGE_TAG=\"${IMAGE_TAG}\" \ + TARGET_ARCH=\"${TARGET_ARCH}\" \ + ITKPYTHONPACKAGE_ORG=\"${ITKPYTHONPACKAGE_ORG}\" \ + ITKPYTHONPACKAGE_TAG=\"${ITKPYTHONPACKAGE_TAG}\" \ + BUILD_WHEELS_EXTRA_FLAGS=\"${BUILD_WHEELS_EXTRA_FLAGS}\" \ + /bin/bash -x ${CONTAINER_PACKAGE_SCRIPTS_DIR}/scripts/docker_build_environment_driver.sh" fi -# Generate dockcross scripts -$oci_exe run --rm docker.io/dockcross/manylinux${MANYLINUX_VERSION}-x64:${IMAGE_TAG} > /tmp/dockcross-manylinux-x64 -chmod u+x /tmp/dockcross-manylinux-x64 - -# Build wheels -pushd $script_dir/.. -mkdir -p dist -DOCKER_ARGS="-v $(pwd)/dist:/work/dist/" -DOCKER_ARGS+=" -e MANYLINUX_VERSION" -/tmp/dockcross-manylinux-x64 \ - -a "$DOCKER_ARGS" \ - ./scripts/internal/manylinux-build-wheels.sh "$@" -popd +echo "RUNNING: $cmd" +eval "$cmd" diff --git a/scripts/dockcross-manylinux-cleanup.sh b/scripts/dockcross-manylinux-cleanup.sh deleted file mode 100755 index 52702518..00000000 --- a/scripts/dockcross-manylinux-cleanup.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -######################################################################## -# Run this script in an ITK external module directory to clean up -# Linux Python build artifacts. -# -# Typically required for building multiple types of module wheels in the same -# directory, such as using different toolsets or targeting different -# architectures. -# -# =========================================== -# ENVIRONMENT VARIABLES -# -# - `ITK_MODULE_PREQ`: Prerequisite ITK modules that must be built before the requested module. -# Format is `/@:/@:...`. -# For instance, `export ITK_MODULE_PREQ=InsightSoftwareConsortium/ITKMeshToPolyData@v0.10.0` -# -# - `NO_SUDO`: Disable the use of superuser permissions for removing directories. -# `sudo` is required by default for cleanup on Github Actions runners. -# -######################################################################## - -echo "Cleaning up artifacts from module build" - -# ARM platform observed to require sudo for removing ITKPythonPackage sources -rm_prefix="" -if [[ ! ${NO_SUDO} ]]; then - rm_prefix="sudo " -fi - -unlink oneTBB-prefix -${rm_prefix} rm -rf ITKPythonPackage/ -${rm_prefix} rm -rf tools/ -${rm_prefix} rm -rf _skbuild/ build/ -${rm_prefix} rm -rf ./*.egg-info/ -${rm_prefix} rm -rf ./ITK-*-manylinux${MANYLINUX_VERSION}_${TARGET_ARCH}/ -${rm_prefix} rm -rf ./ITKPythonBuilds-linux-manylinux*${MANYLINUX_VERSION}*.tar.zst - -if [[ -n ${ITK_MODULE_PREQ} ]]; then - for MODULE_INFO in ${ITK_MODULE_PREQ//:/ }; do - MODULE_NAME=`(echo ${MODULE_INFO} | cut -d'@' -f 1 | cut -d'/' -f 2)` - ${rm_prefix} rm -rf ${MODULE_NAME}/ - done -fi - -# Leave dist/ and download scripts intact diff --git a/scripts/dockcross-manylinux-download-cache-and-build-module-wheels.sh b/scripts/dockcross-manylinux-download-cache-and-build-module-wheels.sh index 37166edd..d94e2d68 100755 --- a/scripts/dockcross-manylinux-download-cache-and-build-module-wheels.sh +++ b/scripts/dockcross-manylinux-download-cache-and-build-module-wheels.sh @@ -16,9 +16,6 @@ # ENVIRONMENT VARIABLES # # These variables are set with the `export` bash command before calling the script. -# For example, -# -# scripts/dockcross-manylinux-build-module-wheels.sh cp310 # # `ITKPYTHONPACKAGE_ORG`: Github organization for fetching ITKPythonPackage build scripts. # @@ -28,11 +25,18 @@ # ######################################################################## +download_script_dir=$( + cd "$(dirname "$0")" || exit 1 + pwd +) +# if not specified, use the current directory for MODULE_SRC_DIRECTORY +MODULE_SRC_DIRECTORY=${MODULE_SRC_DIRECTORY:=${download_script_dir}} +# if not specified then use the a dummy MODULE_DEPENDENCIES directory in the build dashboard +MODULE_DEPS_DIR=${MODULE_DEPS_DIR:=${DASHBOARD_BUILD_DIRECTORY}/MODULE_DEPENDENCIES} # ----------------------------------------------------------------------- # Script argument parsing # -usage() -{ +usage() { echo "Usage: dockcross-manylinux-download-cache-and-build-module-wheels [ -h | --help ] show usage @@ -42,34 +46,111 @@ usage() exit 2 } -FORWARD_ARGS=("$@") # Store arguments to forward them later PARSED_ARGS=$(getopt -a -n dockcross-manylinux-download-cache-and-build-module-wheels \ -o hc:x: --long help,cmake_options:,exclude_libs: -- "$@") eval set -- "$PARSED_ARGS" -while : -do +while :; do case "$1" in - -h | --help) usage; break ;; - -c | --cmake_options) CMAKE_OPTIONS="$2" ; shift 2 ;; - -x | --exclude_libs) EXCLUDE_LIBS="$2" ; shift 2 ;; - --) shift; break ;; - *) echo "Unexpected option: $1."; - usage; break ;; + -h | --help) + usage + ;; + -c | --cmake_options) + export CMAKE_OPTIONS="$2" + shift 2 + ;; + -x | --exclude_libs) + export EXCLUDE_LIBS="$2" + shift 2 + ;; + --) + shift + break + ;; + *) + echo "Unexpected option: $1." + usage + ;; esac done +#For backwards compatibility when the ITK_GIT_TAG was required to match the ITK_PACKAGE_VERSION +ITK_PACKAGE_VERSION=${ITK_PACKAGE_VERSION:="v6.0b02"} +ITK_GIT_TAG=${ITK_GIT_TAG:=${ITK_PACKAGE_VERSION}} + # ----------------------------------------------------------------------- -# Download and extract cache +# Set default values +MANYLINUX_VERSION=${MANYLINUX_VERSION:-_2_28} +TARGET_ARCH=${TARGET_ARCH:-x64} -echo "Fetching https://raw.githubusercontent.com/${ITKPYTHONPACKAGE_ORG:=InsightSoftwareConsortium}/ITKPythonPackage/${ITKPYTHONPACKAGE_TAG:=v5.4.0}/scripts/dockcross-manylinux-download-cache.sh" -curl -L https://raw.githubusercontent.com/${ITKPYTHONPACKAGE_ORG:=InsightSoftwareConsortium}/ITKPythonPackage/${ITKPYTHONPACKAGE_TAG:=v5.4.0}/scripts/dockcross-manylinux-download-cache.sh -O -chmod u+x dockcross-manylinux-download-cache.sh -./dockcross-manylinux-download-cache.sh $1 +ITKPYTHONPACKAGE_ORG=${ITKPYTHONPACKAGE_ORG:-InsightSoftwareConsortium} +ITKPYTHONPACKAGE_TAG=${ITKPYTHONPACKAGE_TAG:-main} + +# ----------------------------------------------------------------------- +# Check for conda/pixi-provided ITK (libitk-wrapping package). +# When available, skip the tarball download entirely. + +_conda_itk_dir="" +for _prefix_var in CONDA_PREFIX PIXI_ENVIRONMENT_DIR; do + _prefix="${!_prefix_var:-}" + if [ -n "${_prefix}" ]; then + for _candidate in "${_prefix}"/lib/cmake/ITK-*; do + if [ -f "${_candidate}/ITKConfig.cmake" ]; then + _conda_itk_dir="${_candidate}" + echo "Detected conda-installed ITK at ${_conda_itk_dir} (via \$${_prefix_var})" + break 2 + fi + done + fi +done + +if [ -n "${_conda_itk_dir}" ]; then + echo "Using conda-installed ITK; skipping tarball download." + # Point to this repo's own scripts (already present on disk) + untarred_ipp_dir=${download_script_dir} + ITK_SOURCE_DIR="" +else + # ----------------------------------------------------------------------- + # Download and extract cache (legacy tarball path) + + echo "Fetching https://raw.githubusercontent.com/${ITKPYTHONPACKAGE_ORG}/ITKPythonPackage/${ITKPYTHONPACKAGE_TAG}/scripts/dockcross-manylinux-download-cache.sh" + curl -L "https://raw.githubusercontent.com/${ITKPYTHONPACKAGE_ORG}/ITKPythonPackage/${ITKPYTHONPACKAGE_TAG}/scripts/dockcross-manylinux-download-cache.sh" -O + chmod u+x dockcross-manylinux-download-cache.sh + _download_cmd="ITK_GIT_TAG=${ITK_GIT_TAG} \ + ITK_PACKAGE_VERSION=${ITK_PACKAGE_VERSION} \ + ITKPYTHONPACKAGE_ORG=${ITKPYTHONPACKAGE_ORG} \ + ITKPYTHONPACKAGE_TAG=${ITKPYTHONPACKAGE_TAG} \ + MANYLINUX_VERSION=${MANYLINUX_VERSION} \ + TARGET_ARCH=${TARGET_ARCH} \ + bash -x \ + ${download_script_dir}/dockcross-manylinux-download-cache.sh $1" + echo "Running: ${_download_cmd}" + eval "${_download_cmd}" + + #NOTE: in this scenario, untarred_ipp_dir is extracted from tarball + # during ${download_script_dir}/dockcross-manylinux-download-cache.sh + untarred_ipp_dir=${download_script_dir}/ITKPythonPackage + + ITK_SOURCE_DIR=${download_script_dir}/ITKPythonPackage-build/ITK +fi # ----------------------------------------------------------------------- # Build module wheels echo "Building module wheels" -set -- "${FORWARD_ARGS[@]}"; # Restore initial argument list -./ITKPythonPackage/scripts/dockcross-manylinux-build-module-wheels.sh "$@" + +_bld_cmd="NO_SUDO=${NO_SUDO} \ + LD_LIBRARY_PATH=${LD_LIBRARY_PATH} \ + IMAGE_TAG=${IMAGE_TAG} \ + TARGET_ARCH=${TARGET_ARCH} \ + ITK_SOURCE_DIR=${ITK_SOURCE_DIR} \ + ITK_GIT_TAG=${ITK_GIT_TAG} \ + ITK_PACKAGE_VERSION=${ITK_PACKAGE_VERSION} \ + ITK_MODULE_PREQ=${ITK_MODULE_PREQ} \ + ITK_MODULE_NO_CLEANUP=${ITK_MODULE_NO_CLEANUP} \ + MODULE_SRC_DIRECTORY=${MODULE_SRC_DIRECTORY} \ + MODULE_DEPS_DIR=${MODULE_DEPS_DIR} \ + MANYLINUX_VERSION=${MANYLINUX_VERSION} \ + ${untarred_ipp_dir}/scripts/dockcross-manylinux-build-module-wheels.sh $*" +echo "Running: ${_bld_cmd}" +eval "${_bld_cmd}" diff --git a/scripts/dockcross-manylinux-download-cache.sh b/scripts/dockcross-manylinux-download-cache.sh index 10d17e2d..d3571228 100755 --- a/scripts/dockcross-manylinux-download-cache.sh +++ b/scripts/dockcross-manylinux-download-cache.sh @@ -11,31 +11,13 @@ # steps not present in `dockcross-manylinux-download-cache-and-build-module-wheels.sh`. # # =========================================== -# ENVIRONMENT VARIABLES -# -# `ITK_PACKAGE_VERSION`: Tag for ITKPythonBuilds build cache to use -# Examples: "v5.4.0", "v5.2.1.post1" -# See available tags at https://github.com/InsightSoftwareConsortium/ITKPythonBuilds/tags -# -# `MANYLINUX_VERSION`: manylinux specialization used to build ITK for cache -# Examples: "_2_28", "2014", "_2_28_aarch64" -# See https://github.com/dockcross/dockcross -# -# `ITKPYTHONPACKAGE_TAG`: Tag for ITKPythonPackage build scripts to use. -# If ITKPYTHONPACKAGE_TAG is empty then the default scripts distributed -# with the ITKPythonBuilds archive will be used. -# -# `ITKPYTHONPACKAGE_ORG`: Github organization or user to use for ITKPythonPackage -# build script source. Default is InsightSoftwareConsortium. -# Ignored if ITKPYTHONPACKAGE_TAG is empty. -# +# ENVIRONMENT VARIABLES: ITK_GIT_TAG, MANYLINUX_VERSION, ITKPYTHONPACKAGE_TAG, ITKPYTHONPACKAGE_ORG ######################################################################## # ----------------------------------------------------------------------- # Script argument parsing # -usage() -{ +usage() { echo "Usage: dockcross-manylinux-download-cache.sh [ -h | --help ] show usage @@ -43,25 +25,53 @@ usage() exit 2 } -FORWARD_ARGS=("$@") # Store arguments to forward them later +# Required environment variables +required_vars=( + ITK_GIT_TAG + ITK_PACKAGE_VERSION + ITKPYTHONPACKAGE_ORG + ITKPYTHONPACKAGE_TAG + MANYLINUX_VERSION + TARGET_ARCH +) + +# Sanity Validation loop +_missing_required=0 +for v in "${required_vars[@]}"; do + if [ -z "${!v:-}" ]; then + _missing_required=1 + echo "ERROR: Required environment variable '$v' is not set or empty." + fi +done +if [ "${_missing_required}" -ne 0 ]; then + exit 1 +fi +unset _missing_required + PARSED_ARGS=$(getopt -a -n dockcross-manylinux-download-cache-and-build-module-wheels \ -o hc:x: --long help,cmake_options:,exclude_libs: -- "$@") eval set -- "$PARSED_ARGS" -while : -do +while :; do case "$1" in - -h | --help) usage; break ;; - --) shift; break ;; - *) echo "Unexpected option: $1."; - usage; break ;; + -h | --help) + usage + ;; + --) + shift + break + ;; + *) + echo "Unexpected option: $1." + usage + ;; esac done # ----------------------------------------------------------------------- # Verify that unzstd binary is available to decompress ITK build archives. -unzstd_exe=`(which unzstd)` +unzstd_exe=$(which unzstd) if [[ -z ${unzstd_exe} ]]; then echo "ERROR: can not find required binary 'unzstd' " @@ -73,42 +83,27 @@ ${unzstd_exe} --version # ----------------------------------------------------------------------- # Fetch build archive - -MANYLINUX_VERSION=${MANYLINUX_VERSION:=_2_28} -TARGET_ARCH=${TARGET_ARCH:=x64} - -case ${TARGET_ARCH} in - x64) - TARBALL_SPECIALIZATION="-manylinux${MANYLINUX_VERSION}" - ;; - *) - TARBALL_SPECIALIZATION="-manylinux${MANYLINUX_VERSION}_${TARGET_ARCH}" - ;; -esac -TARBALL_NAME="ITKPythonBuilds-linux${TARBALL_SPECIALIZATION}.tar" +TARBALL_NAME="ITKPythonBuilds-manylinux${MANYLINUX_VERSION}-${TARGET_ARCH}.tar" if [[ ! -f ${TARBALL_NAME}.zst ]]; then - echo "Fetching https://github.com/InsightSoftwareConsortium/ITKPythonBuilds/releases/download/${ITK_PACKAGE_VERSION:=v5.4.0}/${TARBALL_NAME}.zst" - curl -L https://github.com/InsightSoftwareConsortium/ITKPythonBuilds/releases/download/${ITK_PACKAGE_VERSION:=v5.4.0}/${TARBALL_NAME}.zst -O + echo "Local ITK cache tarball file not found..." + echo "Fetching https://github.com/InsightSoftwareConsortium/ITKPythonBuilds/releases/download/${ITK_PACKAGE_VERSION}/${TARBALL_NAME}.zst" + if ! curl -L "https://github.com/InsightSoftwareConsortium/ITKPythonBuilds/releases/download/${ITK_PACKAGE_VERSION}/${TARBALL_NAME}.zst" -O; then + echo "FAILED Download:" + echo "curl -L https://github.com/InsightSoftwareConsortium/ITKPythonBuilds/releases/download/${ITK_PACKAGE_VERSION}/${TARBALL_NAME}.zst -O" + exit 1 + fi fi if [[ ! -f ./${TARBALL_NAME}.zst ]]; then echo "ERROR: can not find required binary './${TARBALL_NAME}.zst'" exit 255 fi -${unzstd_exe} --long=31 ./${TARBALL_NAME}.zst -o ${TARBALL_NAME} -if [ "$#" -lt 1 ]; then - echo "Extracting all files"; - tar xf ${TARBALL_NAME} -else - echo "Extracting files relevant for: $1"; - tar xf ${TARBALL_NAME} ITKPythonPackage/scripts/ - tar xf ${TARBALL_NAME} ITKPythonPackage/ITK-source/ - tar xf ${TARBALL_NAME} ITKPythonPackage/oneTBB-prefix/ - tar xf ${TARBALL_NAME} --wildcards ITKPythonPackage/ITK-$1* -fi -rm ${TARBALL_NAME} +"${unzstd_exe}" --long=31 "./${TARBALL_NAME}.zst" -o "${TARBALL_NAME}" -ln -s ITKPythonPackage/oneTBB-prefix ./ +current_dir=$(pwd) +echo "Extracting all cache files from ${TARBALL_NAME} in ${current_dir}" +tar xf "${TARBALL_NAME}" --warning=no-unknown-keyword +rm "${TARBALL_NAME}" # ----------------------------------------------------------------------- # Optional: Update build scripts @@ -118,22 +113,22 @@ ln -s ITKPythonPackage/oneTBB-prefix ./ # since the archives were generated. if [[ -n ${ITKPYTHONPACKAGE_TAG} ]]; then - echo "Updating build scripts to ${ITKPYTHONPACKAGE_ORG:=InsightSoftwareConsortium}/ITKPythonPackage@${ITKPYTHONPACKAGE_TAG}" - git clone "https://github.com/${ITKPYTHONPACKAGE_ORG}/ITKPythonPackage.git" "IPP-tmp" + # shellcheck disable=SC2153 + echo "Updating build scripts to ${ITKPYTHONPACKAGE_ORG}/ITKPythonPackage@${ITKPYTHONPACKAGE_TAG}" + git clone "https://github.com/${ITKPYTHONPACKAGE_ORG}/ITKPythonPackage.git" "${current_dir}/IPP-tmp" - pushd IPP-tmp/ + pushd "${current_dir}/IPP-tmp/" || exit git checkout "${ITKPYTHONPACKAGE_TAG}" git status - popd + popd || exit - rm -rf ITKPythonPackage/scripts/ - cp -r IPP-tmp/scripts ITKPythonPackage/ - cp IPP-tmp/requirements-dev.txt ITKPythonPackage/ - rm -rf IPP-tmp/ + rm -rf "${current_dir}/ITKPythonPackage/scripts/" + rsync -av "${current_dir}"/IPP-tmp/ "${current_dir}/ITKPythonPackage/" + rm -rf "${current_dir}/IPP-tmp/" fi -if [[ ! -f ./ITKPythonPackage/scripts/dockcross-manylinux-build-module-wheels.sh ]]; then - echo "ERROR: can not find required binary './ITKPythonPackage/scripts/dockcross-manylinux-build-module-wheels.sh'" +if [[ ! -f ${current_dir}/ITKPythonPackage/scripts/dockcross-manylinux-build-module-wheels.sh ]]; then + echo "ERROR: can not find required binary '${current_dir}/ITKPythonPackage/scripts/dockcross-manylinux-build-module-wheels.sh'" exit 255 fi diff --git a/scripts/dockcross-manylinux-set-vars.sh b/scripts/dockcross-manylinux-set-vars.sh deleted file mode 100755 index f39ce7ab..00000000 --- a/scripts/dockcross-manylinux-set-vars.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -######################################################################## -# Run this script to set common enviroment variables used in building the -# ITK Python wheel packages for Linux. -# -# ENVIRONMENT VARIABLES -# These environment variables will be populated by the script when invoked with `source` -# if their value is not set with `export` before invocation. -# For example, -# -# export ITK_PACKAGE_VERSION=v5.4.0 -# scripts/dockcross-manylinux-set-vars.sh cp310 -# -######################################################################## - -######################################################################## -# ITKPythonBuilds parameters - -# ITKPythonBuilds archive tag to use for ITK build artifacts. -# See https://github.com/insightSoftwareConsortium/ITKpythonbuilds for available tags. -ITK_PACKAGE_VERSION=${ITK_PACKAGE_VERSION:=v6.0b01} - -# Github organization for fetching ITKPythonPackage build scripts -ITKPYTHONPACKAGE_ORG=${ITKPYTHONPACKAGE_ORG:=InsightSoftwareConsortium} - -# ITKPythonPackage tag for fetching build scripts -ITKPYTHONPACKAGE_TAG=${ITKPYTHONPACKAGE_TAG:=main} - -######################################################################## -# Docker image parameters - -# Specialized manylinux image to use for building. Default is _2_28. -# See https://github.com/dockcross/dockcross for available versions and tags. -MANYLINUX_VERSION=${MANYLINUX_VERSION:=_2_28} - -# Target platform architecture (x64, aarch64) -TARGET_ARCH=${TARGET_ARCH:=x64} - -# Specialized manylinux image tag to use for building. -if [[ ${MANYLINUX_VERSION} == _2_28 && ${TARGET_ARCH} == x64 ]]; then - IMAGE_TAG=${IMAGE_TAG:=20260203-3dfb3ff} -elif [[ ${MANYLINUX_VERSION} == _2_28 && ${TARGET_ARCH} == aarch64 ]]; then - IMAGE_TAG=${IMAGE_TAG:=2025.08.12-1} -elif [[ ${MANYLINUX_VERSION} == 2014 ]]; then - IMAGE_TAG=${IMAGE_TAG:=20240304-9e57d2b} -else - echo "Unknown manylinux version ${MANYLINUX_VERSION}" - exit 1; -fi - -# Set container for requested version/arch/tag. -if [[ ${TARGET_ARCH} == x64 ]]; then - MANYLINUX_IMAGE_NAME=${MANYLINUX_IMAGE_NAME:="manylinux${MANYLINUX_VERSION}-${TARGET_ARCH}:${IMAGE_TAG}"} - CONTAINER_SOURCE="docker.io/dockcross/${MANYLINUX_IMAGE_NAME}" -elif [[ ${TARGET_ARCH} == aarch64 ]]; then - MANYLINUX_IMAGE_NAME=${MANYLINUX_IMAGE_NAME:="manylinux${MANYLINUX_VERSION}_${TARGET_ARCH}:${IMAGE_TAG}"} - CONTAINER_SOURCE="quay.io/pypa/${MANYLINUX_IMAGE_NAME}" -else - echo "Unknown target architecture ${TARGET_ARCH}" - exit 1; -fi diff --git a/scripts/docker_build_environment_driver.sh b/scripts/docker_build_environment_driver.sh new file mode 100755 index 00000000..47dc611a --- /dev/null +++ b/scripts/docker_build_environment_driver.sh @@ -0,0 +1,100 @@ +#!/bin/bash + +# Required environment variables +required_vars=( + ITK_GIT_TAG + MANYLINUX_VERSION + IMAGE_TAG + TARGET_ARCH + ITKPYTHONPACKAGE_ORG + ITKPYTHONPACKAGE_TAG + PY_ENVS +) +# Sanity Validation loop +_missing_required=0 +for v in "${required_vars[@]}"; do + if [ -z "${!v:-}" ]; then + _missing_required=1 + echo "ERROR: Required environment variable '$v' is not set or empty." + fi +done +if [ "${_missing_required}" -ne 0 ]; then + exit 1 +fi +unset _missing_required + +# ----------------------------------------------------------------------- +# Set up paths +# These paths are inside the container + +CONTAINER_WORK_DIR=/work +cd "${CONTAINER_WORK_DIR}" || exit +CONTAINER_PACKAGE_BUILD_DIR=${CONTAINER_WORK_DIR}/ITKPythonPackage-build +CONTAINER_PACKAGE_SCRIPTS_DIR=${CONTAINER_WORK_DIR}/ITKPythonPackage +CONTAINER_MODULE_SRC_DIRECTORY=${CONTAINER_WORK_DIR}/$(basename "${MODULE_SRC_DIRECTORY}") +CONTAINER_ITK_SOURCE_DIR=${CONTAINER_PACKAGE_BUILD_DIR}/ITK +BUILD_WHEELS_EXTRA_FLAGS=${BUILD_WHEELS_EXTRA_FLAGS:=""} +read -ra BUILD_WHEELS_EXTRA_FLAGS_ARRAY <<<"${BUILD_WHEELS_EXTRA_FLAGS}" + +echo "BUILD FOR ${PY_ENVS}" +read -ra PY_ENVS_ARRAY <<<"${PY_ENVS}" + +for py_indicator in "${PY_ENVS_ARRAY[@]}"; do + py_squashed_numeric="${py_indicator//py/}" + py_squashed_numeric="${py_squashed_numeric//cp/}" + py_squashed_numeric="${py_squashed_numeric//./}" + manylinux_vername="${MANYLINUX_VERSION//_/}" + PIXI_ENV="manylinux${manylinux_vername}-py${py_squashed_numeric}" + + # Use pixi to ensure all required tools are installed and + # visible in the PATH + export PIXI_HOME=${CONTAINER_PACKAGE_SCRIPTS_DIR}/.pixi + export PATH="${PIXI_HOME}/bin:${PATH}" + python3.12 "${CONTAINER_PACKAGE_SCRIPTS_DIR}/scripts/install_pixi.py" --platform-env "${PIXI_ENV}" + + cd "${CONTAINER_PACKAGE_SCRIPTS_DIR}" || exit + if [ -n "${MODULE_SRC_DIRECTORY}" ]; then + pixi run -e "${PIXI_ENV}" python3 \ + "${CONTAINER_PACKAGE_SCRIPTS_DIR}/scripts/build_wheels.py" \ + --platform-env "${PIXI_ENV}" \ + "${BUILD_WHEELS_EXTRA_FLAGS_ARRAY[@]}" \ + --module-source-dir "${CONTAINER_MODULE_SRC_DIRECTORY}" \ + --module-dependencies-root-dir "${CONTAINER_MODULES_ROOT_DIRECTORY}" \ + --itk-module-deps "${ITK_MODULE_PREQ}" \ + --no-build-itk-tarball-cache \ + --build-dir-root "${CONTAINER_PACKAGE_BUILD_DIR}" \ + --itk-source-dir "${CONTAINER_ITK_SOURCE_DIR}" \ + --itk-git-tag "${ITK_GIT_TAG}" \ + --itk-package-version "${ITK_PACKAGE_VERSION:-}" \ + --manylinux-version "${MANYLINUX_VERSION}" \ + --no-use-sudo \ + --no-use-ccache \ + --skip-itk-build \ + --skip-itk-wheel-build + else + pixi run -e "${PIXI_ENV}" python3 \ + "${CONTAINER_PACKAGE_SCRIPTS_DIR}/scripts/build_wheels.py" \ + --platform-env "${PIXI_ENV}" \ + "${BUILD_WHEELS_EXTRA_FLAGS_ARRAY[@]}" \ + --build-itk-tarball-cache \ + --build-dir-root "${CONTAINER_PACKAGE_BUILD_DIR}" \ + --itk-source-dir "${CONTAINER_ITK_SOURCE_DIR}" \ + --itk-git-tag "${ITK_GIT_TAG}" \ + --itk-package-version "${ITK_PACKAGE_VERSION:-}" \ + --manylinux-version "${MANYLINUX_VERSION}" \ + --no-use-sudo \ + --no-use-ccache + fi + build_status=$? + if [ "${build_status}" -ne 0 ]; then + echo "ERROR: Build failed for ${py_indicator} with exit code ${build_status}" + exit "${build_status}" + fi + + echo "Successfully built wheel for ${py_indicator}" +done + +echo "" +echo "========================================" +echo "All builds completed successfully!" +echo "========================================" diff --git a/scripts/install_pixi.py b/scripts/install_pixi.py new file mode 100755 index 00000000..986e7629 --- /dev/null +++ b/scripts/install_pixi.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python3 + +import os +from pathlib import Path + +from wheel_builder_utils import detect_platform, run_commandLine_subprocess + + +def download_and_install_pixi( + binary_ext: str, os_name: str, pixi_home: Path, platform_env: str = "default" +) -> Path: + """Download pixi (if not already present) and install a platform environment. + + Parameters + ---------- + binary_ext : str + Executable extension (``'.exe'`` on Windows, ``''`` elsewhere). + os_name : str + Operating system name (``'windows'``, ``'linux'``, ``'darwin'``). + pixi_home : Path + Directory where pixi is (or will be) installed. + platform_env : str, optional + Pixi environment name to install (default ``'default'``). + + Returns + ------- + pixi_exec_path : Path + Path to the pixi executable. + + Raises + ------ + RuntimeError + If the download, installation, or environment setup fails. + """ + pixi_bin_name: str = "pixi" + binary_ext + # Attempt to find an existing pixi binary on the system first (cross-platform) + pixi_exec_path: Path = Path(pixi_home) / "bin" / pixi_bin_name + + pixi_install_env = os.environ.copy() + pixi_install_env["PIXI_NO_PATH_UPDATE"] = "1" + pixi_install_env["PIXI_HOME"] = str(pixi_home) + + # If not found, we will install into the local build .pixi + if pixi_exec_path.is_file(): + print(f"Previous install of pixi will be used {pixi_exec_path}.") + else: + if os_name == "windows": + # Use PowerShell to install pixi on Windows + result = run_commandLine_subprocess( + [ + "powershell", + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-Command", + "irm -UseBasicParsing https://pixi.sh/install.ps1 | iex", + ], + env=pixi_install_env, + ) + if result.returncode != 0: + raise RuntimeError(f"Failed to install pixi: {result.stderr}") + else: + pixi_install_script: Path = pixi_home / "pixi_install.sh" + result = run_commandLine_subprocess( + [ + "curl", + "-fsSL", + "https://pixi.sh/install.sh", + "-o", + str(pixi_install_script), + ] + ) + if result.returncode != 0: + raise RuntimeError( + f"Failed to download {pixi_install_script}: {result.stderr}" + ) + result = run_commandLine_subprocess( + [ + "/bin/sh", + str(pixi_install_script), + ], + env=pixi_install_env, + ) + if result.returncode != 0: + raise RuntimeError(f"Failed to install pixi: {result.stderr}") + del pixi_install_script + + if not pixi_exec_path.exists(): + raise RuntimeError( + f"Failed to install {pixi_exec_path} pixi into {pixi_exec_path}" + ) + # Now install the desired platform + if (pixi_home.parent / "pixi.toml").exists(): + result = run_commandLine_subprocess( + [pixi_exec_path, "install", "--environment", platform_env], + cwd=pixi_home.parent, + env=pixi_install_env, + ) + if result.returncode != 0: + raise RuntimeError( + f"Failed to install environment {platform_env}: {result.stderr}" + ) + else: + print( + f"pixi.toml not found {pixi_home.parent / 'pixi.toml'}, skipping environment install." + ) + return pixi_exec_path + + +def install_pixi_tools(platform_env: str = "default"): + """High-level helper: detect the platform, install pixi, and set up *platform_env*. + + Parameters + ---------- + platform_env : str, optional + Pixi environment name to install (default ``'default'``). + """ + _ipp_dir_path: Path = Path(__file__).resolve().parent.parent + os_name, arch = detect_platform() + binary_ext: str = ".exe" if os_name == "windows" else "" + + pixi_home: Path = Path( + os.environ.get("PIXI_HOME") + if "PIXI_HOME" in os.environ + else _ipp_dir_path / ".pixi" + ) + pixi_home.mkdir(parents=True, exist_ok=True) + pixi_exec_path = Path( + download_and_install_pixi(binary_ext, os_name, pixi_home, platform_env) + ) + print(f"Installed pixi locally to {pixi_home} with binary of {pixi_exec_path}") + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser( + description="Driver script to build ITK Python wheels." + ) + parser.add_argument( + "--platform-env", + default="default", + help=( + """A platform environment name or path: + linux-py310, linux-py311, + manylinux228-py310, manylinux228-py311, + windows-py310, windows-py311, + macosx-py310, macosx-py311 + """ + ), + ) + args = parser.parse_args() + install_pixi_tools(args.platform_env) diff --git a/scripts/internal/Support.cmake b/scripts/internal/Support.cmake deleted file mode 100644 index 84487a32..00000000 --- a/scripts/internal/Support.cmake +++ /dev/null @@ -1,2749 +0,0 @@ -# Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing for details. - -# -# This file is a "template" file used by various FindPython modules. -# - -cmake_policy (GET CMP0094 _${_PYTHON_PREFIX}_LOOKUP_POLICY) - -cmake_policy (VERSION 3.7) - -if (_${_PYTHON_PREFIX}_LOOKUP_POLICY) - cmake_policy (SET CMP0094 ${_${_PYTHON_PREFIX}_LOOKUP_POLICY}) -endif() - -# -# Initial configuration -# -if (NOT DEFINED _PYTHON_PREFIX) - message (FATAL_ERROR "FindPython: INTERNAL ERROR") -endif() -if (NOT DEFINED _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) - message (FATAL_ERROR "FindPython: INTERNAL ERROR") -endif() -if (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL "3") - set(_${_PYTHON_PREFIX}_VERSIONS 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0) -elseif (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL "2") - set(_${_PYTHON_PREFIX}_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0) -else() - message (FATAL_ERROR "FindPython: INTERNAL ERROR") -endif() - -get_property(_${_PYTHON_PREFIX}_CMAKE_ROLE GLOBAL PROPERTY CMAKE_ROLE) - - -# -# helper commands -# -macro (_PYTHON_DISPLAY_FAILURE _PYTHON_MSG) - if (${_PYTHON_PREFIX}_FIND_REQUIRED) - message (FATAL_ERROR "${_PYTHON_MSG}") - else() - if (NOT ${_PYTHON_PREFIX}_FIND_QUIETLY) - message(STATUS "${_PYTHON_MSG}") - endif () - endif() - - set (${_PYTHON_PREFIX}_FOUND FALSE) - string (TOUPPER "${_PYTHON_PREFIX}" _${_PYTHON_PREFIX}_UPPER_PREFIX) - set (${_PYTHON_UPPER_PREFIX}_FOUND FALSE) - return() -endmacro() - - -function (_PYTHON_MARK_AS_INTERNAL) - foreach (var IN LISTS ARGV) - if (DEFINED CACHE{${var}}) - set_property (CACHE ${var} PROPERTY TYPE INTERNAL) - endif() - endforeach() -endfunction() - - -macro (_PYTHON_SELECT_LIBRARY_CONFIGURATIONS _PYTHON_BASENAME) - if(NOT DEFINED ${_PYTHON_BASENAME}_LIBRARY_RELEASE) - set(${_PYTHON_BASENAME}_LIBRARY_RELEASE "${_PYTHON_BASENAME}_LIBRARY_RELEASE-NOTFOUND") - endif() - if(NOT DEFINED ${_PYTHON_BASENAME}_LIBRARY_DEBUG) - set(${_PYTHON_BASENAME}_LIBRARY_DEBUG "${_PYTHON_BASENAME}_LIBRARY_DEBUG-NOTFOUND") - endif() - - get_property(_PYTHON_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) - if (${_PYTHON_BASENAME}_LIBRARY_DEBUG AND ${_PYTHON_BASENAME}_LIBRARY_RELEASE AND - NOT ${_PYTHON_BASENAME}_LIBRARY_DEBUG STREQUAL ${_PYTHON_BASENAME}_LIBRARY_RELEASE AND - (_PYTHON_isMultiConfig OR CMAKE_BUILD_TYPE)) - # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for - # single-config generators, set optimized and debug libraries - set (${_PYTHON_BASENAME}_LIBRARIES "") - foreach (_PYTHON_libname IN LISTS ${_PYTHON_BASENAME}_LIBRARY_RELEASE) - list( APPEND ${_PYTHON_BASENAME}_LIBRARIES optimized "${_PYTHON_libname}") - endforeach() - foreach (_PYTHON_libname IN LISTS ${_PYTHON_BASENAME}_LIBRARY_DEBUG) - list( APPEND ${_PYTHON_BASENAME}_LIBRARIES debug "${_PYTHON_libname}") - endforeach() - elseif (${_PYTHON_BASENAME}_LIBRARY_RELEASE) - set (${_PYTHON_BASENAME}_LIBRARIES "${${_PYTHON_BASENAME}_LIBRARY_RELEASE}") - elseif (${_PYTHON_BASENAME}_LIBRARY_DEBUG) - set (${_PYTHON_BASENAME}_LIBRARIES "${${_PYTHON_BASENAME}_LIBRARY_DEBUG}") - else() - set (${_PYTHON_BASENAME}_LIBRARIES "${_PYTHON_BASENAME}_LIBRARY-NOTFOUND") - endif() -endmacro() - - -macro (_PYTHON_FIND_FRAMEWORKS) - set (${_PYTHON_PREFIX}_FRAMEWORKS) - if (CMAKE_HOST_APPLE OR APPLE) - file(TO_CMAKE_PATH "$ENV{CMAKE_FRAMEWORK_PATH}" _pff_CMAKE_FRAMEWORK_PATH) - set (_pff_frameworks ${CMAKE_FRAMEWORK_PATH} - ${_pff_CMAKE_FRAMEWORK_PATH} - ~/Library/Frameworks - /usr/local/Frameworks - ${CMAKE_SYSTEM_FRAMEWORK_PATH}) - list (REMOVE_DUPLICATES _pff_frameworks) - foreach (_pff_framework IN LISTS _pff_frameworks) - if (EXISTS ${_pff_framework}/Python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}.framework) - list (APPEND ${_PYTHON_PREFIX}_FRAMEWORKS ${_pff_framework}/Python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}.framework) - endif() - if (EXISTS ${_pff_framework}/Python.framework) - list (APPEND ${_PYTHON_PREFIX}_FRAMEWORKS ${_pff_framework}/Python.framework) - endif() - endforeach() - unset (_pff_frameworks) - unset (_pff_framework) - endif() -endmacro() - -function (_PYTHON_GET_FRAMEWORKS _PYTHON_PGF_FRAMEWORK_PATHS _PYTHON_VERSION) - set (_PYTHON_FRAMEWORK_PATHS) - foreach (_PYTHON_FRAMEWORK IN LISTS ${_PYTHON_PREFIX}_FRAMEWORKS) - list (APPEND _PYTHON_FRAMEWORK_PATHS - "${_PYTHON_FRAMEWORK}/Versions/${_PYTHON_VERSION}") - endforeach() - set (${_PYTHON_PGF_FRAMEWORK_PATHS} ${_PYTHON_FRAMEWORK_PATHS} PARENT_SCOPE) -endfunction() - -function (_PYTHON_GET_REGISTRIES _PYTHON_PGR_REGISTRY_PATHS _PYTHON_VERSION) - string (REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${_PYTHON_VERSION}) - set (${_PYTHON_PGR_REGISTRY_PATHS} - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_PYTHON_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_PYTHON_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_PYTHON_VERSION}\\InstallPath] - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_PYTHON_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_PYTHON_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_PYTHON_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_PYTHON_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_PYTHON_VERSION}\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_PYTHON_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_PYTHON_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] - PARENT_SCOPE) -endfunction() - - -function (_PYTHON_GET_ABIFLAGS _PGABIFLAGS) - set (abiflags) - list (GET _${_PYTHON_PREFIX}_FIND_ABI 0 pydebug) - list (GET _${_PYTHON_PREFIX}_FIND_ABI 1 pymalloc) - list (GET _${_PYTHON_PREFIX}_FIND_ABI 2 unicode) - - if (pymalloc STREQUAL "ANY" AND unicode STREQUAL "ANY") - set (abiflags "mu" "m" "u" "") - elseif (pymalloc STREQUAL "ANY" AND unicode STREQUAL "ON") - set (abiflags "mu" "u") - elseif (pymalloc STREQUAL "ANY" AND unicode STREQUAL "OFF") - set (abiflags "m" "") - elseif (pymalloc STREQUAL "ON" AND unicode STREQUAL "ANY") - set (abiflags "mu" "m") - elseif (pymalloc STREQUAL "ON" AND unicode STREQUAL "ON") - set (abiflags "mu") - elseif (pymalloc STREQUAL "ON" AND unicode STREQUAL "OFF") - set (abiflags "m") - elseif (pymalloc STREQUAL "ON" AND unicode STREQUAL "ANY") - set (abiflags "u" "") - elseif (pymalloc STREQUAL "OFF" AND unicode STREQUAL "ON") - set (abiflags "u") - endif() - - if (pydebug STREQUAL "ON") - if (abiflags) - list (TRANSFORM abiflags PREPEND "d") - else() - set (abiflags "d") - endif() - elseif (pydebug STREQUAL "ANY") - if (abiflags) - set (flags "${abiflags}") - list (TRANSFORM flags PREPEND "d") - list (APPEND abiflags "${flags}") - else() - set (abiflags "" "d") - endif() - endif() - - set (${_PGABIFLAGS} "${abiflags}" PARENT_SCOPE) -endfunction() - -function (_PYTHON_GET_PATH_SUFFIXES _PYTHON_PGPS_PATH_SUFFIXES) - cmake_parse_arguments (PARSE_ARGV 1 _PGPS "LIBRARY;INCLUDE" "VERSION" "") - - if (DEFINED _${_PYTHON_PREFIX}_ABIFLAGS) - set (abi "${_${_PYTHON_PREFIX}_ABIFLAGS}") - else() - set (abi "mu" "m" "u" "") - endif() - - set (path_suffixes) - if (_PGPS_LIBRARY) - if (CMAKE_LIBRARY_ARCHITECTURE) - list (APPEND path_suffixes lib/${CMAKE_LIBRARY_ARCHITECTURE}) - endif() - list (APPEND path_suffixes lib libs) - - if (CMAKE_LIBRARY_ARCHITECTURE) - set (suffixes "${abi}") - if (suffixes) - list (TRANSFORM suffixes PREPEND "lib/python${_PGPS_VERSION}/config-${_PGPS_VERSION}") - list (TRANSFORM suffixes APPEND "-${CMAKE_LIBRARY_ARCHITECTURE}") - else() - set (suffixes "lib/python${_PGPS_VERSION}/config-${_PGPS_VERSION}-${CMAKE_LIBRARY_ARCHITECTURE}") - endif() - list (APPEND path_suffixes ${suffixes}) - endif() - set (suffixes "${abi}") - if (suffixes) - list (TRANSFORM suffixes PREPEND "lib/python${_PGPS_VERSION}/config-${_PGPS_VERSION}") - else() - set (suffixes "lib/python${_PGPS_VERSION}/config-${_PGPS_VERSION}") - endif() - list (APPEND path_suffixes ${suffixes}) - elseif (_PGPS_INCLUDE) - set (suffixes "${abi}") - if (suffixes) - list (TRANSFORM suffixes PREPEND "include/python${_PGPS_VERSION}") - else() - set (suffixes "include/python${_PGPS_VERSION}") - endif() - list (APPEND path_suffixes ${suffixes} include) - endif() - - set (${_PYTHON_PGPS_PATH_SUFFIXES} ${path_suffixes} PARENT_SCOPE) -endfunction() - -function (_PYTHON_GET_NAMES _PYTHON_PGN_NAMES) - cmake_parse_arguments (PARSE_ARGV 1 _PGN "POSIX;EXECUTABLE;CONFIG;LIBRARY;WIN32;DEBUG" "VERSION" "") - - set (names) - - if (_PGN_WIN32) - string (REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${_PGN_VERSION}) - - set (name python${_PYTHON_VERSION_NO_DOTS}) - if (_PGN_DEBUG) - string (APPEND name "_d") - endif() - - list (APPEND names "${name}") - endif() - - if (_PGN_POSIX) - if (DEFINED _${_PYTHON_PREFIX}_ABIFLAGS) - set (abi "${_${_PYTHON_PREFIX}_ABIFLAGS}") - else() - if (_PGN_EXECUTABLE OR _PGN_CONFIG) - set (abi "") - else() - set (abi "mu" "m" "u" "") - endif() - endif() - - if (abi) - if (_PGN_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE) - set (abinames "${abi}") - list (TRANSFORM abinames PREPEND "${CMAKE_LIBRARY_ARCHITECTURE}-python${_PGN_VERSION}") - list (TRANSFORM abinames APPEND "-config") - list (APPEND names ${abinames}) - endif() - set (abinames "${abi}") - list (TRANSFORM abinames PREPEND "python${_PGN_VERSION}") - if (_PGN_CONFIG) - list (TRANSFORM abinames APPEND "-config") - endif() - list (APPEND names ${abinames}) - else() - if (_PGN_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE) - set (abinames "${CMAKE_LIBRARY_ARCHITECTURE}-python${_PGN_VERSION}") - endif() - list (APPEND abinames "python${_PGN_VERSION}") - if (_PGN_CONFIG) - list (TRANSFORM abinames APPEND "-config") - endif() - list (APPEND names ${abinames}) - endif() - endif() - - set (${_PYTHON_PGN_NAMES} ${names} PARENT_SCOPE) -endfunction() - -function (_PYTHON_GET_CONFIG_VAR _PYTHON_PGCV_VALUE NAME) - unset (${_PYTHON_PGCV_VALUE} PARENT_SCOPE) - - if (NOT NAME MATCHES "^(PREFIX|ABIFLAGS|CONFIGDIR|INCLUDES|LIBS|SOABI)$") - return() - endif() - - if (_${_PYTHON_PREFIX}_CONFIG) - if (NAME STREQUAL "SOABI") - set (config_flag "--extension-suffix") - else() - set (config_flag "--${NAME}") - endif() - string (TOLOWER "${config_flag}" config_flag) - execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" ${config_flag} - RESULT_VARIABLE _result - OUTPUT_VARIABLE _values - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if (_result) - unset (_values) - else() - if (NAME STREQUAL "INCLUDES") - # do some clean-up - string (REGEX MATCHALL "(-I|-iwithsysroot)[ ]*[^ ]+" _values "${_values}") - string (REGEX REPLACE "(-I|-iwithsysroot)[ ]*" "" _values "${_values}") - list (REMOVE_DUPLICATES _values) - elseif (NAME STREQUAL "SOABI") - # clean-up: remove prefix character and suffix - string (REGEX REPLACE "^[.-](.+)(${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.(so|pyd))$" "\\1" _values "${_values}") - endif() - endif() - endif() - - if (_${_PYTHON_PREFIX}_EXECUTABLE AND NOT CMAKE_CROSSCOMPILING) - if (NAME STREQUAL "PREFIX") - execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(';'.join([sysconfig.PREFIX,sysconfig.EXEC_PREFIX,sysconfig.BASE_EXEC_PREFIX]))\nexcept Exception:\n import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_config_var('base') or '', sysconfig.get_config_var('installed_base') or '']))" - RESULT_VARIABLE _result - OUTPUT_VARIABLE _values - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if (_result) - unset (_values) - else() - list (REMOVE_DUPLICATES _values) - endif() - elseif (NAME STREQUAL "INCLUDES") - if (WIN32) - set (_scheme "nt") - else() - set (_scheme "posix_prefix") - endif() - execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_python_inc(plat_specific=True),sysconfig.get_python_inc(plat_specific=False)]))\nexcept Exception:\n import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_path('platinclude'),sysconfig.get_path('platinclude','${_scheme}'),sysconfig.get_path('include'),sysconfig.get_path('include','${_scheme}')]))" - RESULT_VARIABLE _result - OUTPUT_VARIABLE _values - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if (_result) - unset (_values) - else() - list (REMOVE_DUPLICATES _values) - endif() - elseif (NAME STREQUAL "SOABI") - execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_config_var('SOABI') or '',sysconfig.get_config_var('EXT_SUFFIX') or '']))\nexcept Exception:\n import sysconfig;sys.stdout.write(';'.join([sysconfig.get_config_var('SOABI') or '',sysconfig.get_config_var('EXT_SUFFIX') or '']))" - RESULT_VARIABLE _result - OUTPUT_VARIABLE _soabi - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if (_result) - unset (_values) - else() - foreach (_item IN LISTS _soabi) - if (_item) - set (_values "${_item}") - break() - endif() - endforeach() - if (_values) - # clean-up: remove prefix character and suffix - string (REGEX REPLACE "^[.-](.+)(${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.(so|pyd))$" "\\1" _values "${_values}") - endif() - endif() - else() - set (config_flag "${NAME}") - if (NAME STREQUAL "CONFIGDIR") - set (config_flag "LIBPL") - endif() - execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(sysconfig.get_config_var('${config_flag}'))\nexcept Exception:\n import sysconfig\n sys.stdout.write(sysconfig.get_config_var('${config_flag}'))" - RESULT_VARIABLE _result - OUTPUT_VARIABLE _values - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if (_result) - unset (_values) - endif() - endif() - endif() - - if (config_flag STREQUAL "ABIFLAGS") - set (${_PYTHON_PGCV_VALUE} "${_values}" PARENT_SCOPE) - return() - endif() - - if (NOT _values OR _values STREQUAL "None") - return() - endif() - - if (NAME STREQUAL "LIBS") - # do some clean-up - string (REGEX MATCHALL "-(l|framework)[ ]*[^ ]+" _values "${_values}") - # remove elements relative to python library itself - list (FILTER _values EXCLUDE REGEX "-lpython") - list (REMOVE_DUPLICATES _values) - endif() - - if (WIN32 AND NAME MATCHES "^(PREFIX|CONFIGDIR|INCLUDES)$") - file (TO_CMAKE_PATH "${_values}" _values) - endif() - - set (${_PYTHON_PGCV_VALUE} "${_values}" PARENT_SCOPE) -endfunction() - -function (_PYTHON_GET_VERSION) - cmake_parse_arguments (PARSE_ARGV 0 _PGV "LIBRARY;INCLUDE" "PREFIX" "") - - unset (${_PGV_PREFIX}VERSION PARENT_SCOPE) - unset (${_PGV_PREFIX}VERSION_MAJOR PARENT_SCOPE) - unset (${_PGV_PREFIX}VERSION_MINOR PARENT_SCOPE) - unset (${_PGV_PREFIX}VERSION_PATCH PARENT_SCOPE) - unset (${_PGV_PREFIX}ABI PARENT_SCOPE) - - if (_PGV_LIBRARY) - # retrieve version and abi from library name - if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE) - # extract version from library name - if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "python([23])([0-9]+)") - set (${_PGV_PREFIX}VERSION_MAJOR "${CMAKE_MATCH_1}" PARENT_SCOPE) - set (${_PGV_PREFIX}VERSION_MINOR "${CMAKE_MATCH_2}" PARENT_SCOPE) - set (${_PGV_PREFIX}VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}" PARENT_SCOPE) - set (${_PGV_PREFIX}ABI "" PARENT_SCOPE) - elseif (_${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "python([23])\\.([0-9]+)([dmu]*)") - set (${_PGV_PREFIX}VERSION_MAJOR "${CMAKE_MATCH_1}" PARENT_SCOPE) - set (${_PGV_PREFIX}VERSION_MINOR "${CMAKE_MATCH_2}" PARENT_SCOPE) - set (${_PGV_PREFIX}VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}" PARENT_SCOPE) - set (${_PGV_PREFIX}ABI "${CMAKE_MATCH_3}" PARENT_SCOPE) - endif() - endif() - else() - if (_${_PYTHON_PREFIX}_INCLUDE_DIR) - # retrieve version from header file - file (STRINGS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}/patchlevel.h" version - REGEX "^#define[ \t]+PY_VERSION[ \t]+\"[^\"]+\"") - string (REGEX REPLACE "^#define[ \t]+PY_VERSION[ \t]+\"([^\"]+)\".*" "\\1" - version "${version}") - string (REGEX MATCHALL "[0-9]+" versions "${version}") - list (GET versions 0 version_major) - list (GET versions 1 version_minor) - list (GET versions 2 version_patch) - - set (${_PGV_PREFIX}VERSION "${version_major}.${version_minor}" PARENT_SCOPE) - set (${_PGV_PREFIX}VERSION_MAJOR ${version_major} PARENT_SCOPE) - set (${_PGV_PREFIX}VERSION_MINOR ${version_minor} PARENT_SCOPE) - set (${_PGV_PREFIX}VERSION_PATCH ${version_patch} PARENT_SCOPE) - - # compute ABI flags - if (version_major VERSION_GREATER "2") - file (STRINGS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}/pyconfig.h" config REGEX "(Py_DEBUG|WITH_PYMALLOC|Py_UNICODE_SIZE|MS_WIN32)") - set (abi) - if (config MATCHES "#[ ]*define[ ]+MS_WIN32") - # ABI not used on Windows - set (abi "") - else() - if (config MATCHES "#[ ]*define[ ]+Py_DEBUG[ ]+1") - string (APPEND abi "d") - endif() - if (config MATCHES "#[ ]*define[ ]+WITH_PYMALLOC[ ]+1") - string (APPEND abi "m") - endif() - if (config MATCHES "#[ ]*define[ ]+Py_UNICODE_SIZE[ ]+4") - string (APPEND abi "u") - endif() - set (${_PGV_PREFIX}ABI "${abi}" PARENT_SCOPE) - endif() - else() - # ABI not supported - set (${_PGV_PREFIX}ABI "" PARENT_SCOPE) - endif() - endif() - endif() -endfunction() - - -function (_PYTHON_VALIDATE_INTERPRETER) - if (NOT _${_PYTHON_PREFIX}_EXECUTABLE) - return() - endif() - - cmake_parse_arguments (PARSE_ARGV 0 _PVI "EXACT;CHECK_EXISTS" "" "") - if (_PVI_UNPARSED_ARGUMENTS) - set (expected_version ${_PVI_UNPARSED_ARGUMENTS}) - else() - unset (expected_version) - endif() - - if (_PVI_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_EXECUTABLE}") - # interpreter does not exist anymore - set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot find the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"") - set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") - return() - endif() - - # validate ABI compatibility - if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI) - execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c - "import sys; sys.stdout.write(sys.abiflags)" - RESULT_VARIABLE result - OUTPUT_VARIABLE abi - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if (result) - # assume ABI is not supported - set (abi "") - endif() - if (NOT abi IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS) - # incompatible ABI - set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong ABI for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"") - set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") - return() - endif() - endif() - - get_filename_component (python_name "${_${_PYTHON_PREFIX}_EXECUTABLE}" NAME) - - if (expected_version AND NOT python_name STREQUAL "python${expected_version}${abi}${CMAKE_EXECUTABLE_SUFFIX}") - # executable found must have a specific version - execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c - "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:2]]))" - RESULT_VARIABLE result - OUTPUT_VARIABLE version - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if (result) - # interpreter is not usable - set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"") - set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") - else() - if (_PVI_EXACT AND NOT version VERSION_EQUAL expected_version) - # interpreter has wrong version - set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"") - set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") - else() - # check that version is OK - string(REGEX REPLACE "^([0-9]+)\\..*$" "\\1" major_version "${version}") - string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" expected_major_version "${expected_version}") - if (NOT major_version VERSION_EQUAL expected_major_version - OR NOT version VERSION_GREATER_EQUAL expected_version) - set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"") - set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") - endif() - endif() - endif() - if (NOT _${_PYTHON_PREFIX}_EXECUTABLE) - return() - endif() - else() - if (NOT python_name STREQUAL "python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}${CMAKE_EXECUTABLE_SUFFIX}") - # executable found do not have version in name - # ensure major version is OK - execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c - "import sys; sys.stdout.write(str(sys.version_info[0]))" - RESULT_VARIABLE result - OUTPUT_VARIABLE version - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if (result OR NOT version EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) - # interpreter not usable or has wrong major version - if (result) - set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"") - else() - set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong major version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"") - endif() - set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") - return() - endif() - endif() - endif() - - if (CMAKE_SIZEOF_VOID_P AND ("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS - OR "Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) - AND NOT CMAKE_CROSSCOMPILING) - # In this case, interpreter must have same architecture as environment - execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c - "import sys, struct; sys.stdout.write(str(struct.calcsize(\"P\")))" - RESULT_VARIABLE result - OUTPUT_VARIABLE size - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if (result OR NOT size EQUAL CMAKE_SIZEOF_VOID_P) - # interpreter not usable or has wrong architecture - if (result) - set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"") - else() - set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong architecture for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"") - endif() - set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") - return() - endif() - endif() -endfunction() - - -function (_PYTHON_VALIDATE_COMPILER expected_version) - if (NOT _${_PYTHON_PREFIX}_COMPILER) - return() - endif() - - cmake_parse_arguments (_PVC "EXACT;CHECK_EXISTS" "" "" ${ARGN}) - if (_PVC_UNPARSED_ARGUMENTS) - set (major_version FALSE) - set (expected_version ${_PVC_UNPARSED_ARGUMENTS}) - else() - set (major_version TRUE) - set (expected_version ${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}) - set (_PVC_EXACT TRUE) - endif() - - if (_PVC_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_COMPILER}") - # Compiler does not exist anymore - set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Cannot find the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"") - set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND") - return() - endif() - - # retrieve python environment version from compiler - set (working_dir "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/PythonCompilerVersion.dir") - if (major_version) - # check only major version - file (WRITE "${working_dir}/version.py" "import sys; sys.stdout.write(str(sys.version_info[0]))") - else() - file (WRITE "${working_dir}/version.py" "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:2]]))\n") - endif() - execute_process (COMMAND "${_${_PYTHON_PREFIX}_COMPILER}" /target:exe /embed "${working_dir}/version.py" - WORKING_DIRECTORY "${working_dir}" - OUTPUT_QUIET - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - execute_process (COMMAND "${working_dir}/version" - WORKING_DIRECTORY "${working_dir}" - RESULT_VARIABLE result - OUTPUT_VARIABLE version - ERROR_QUIET) - file (REMOVE_RECURSE "${_${_PYTHON_PREFIX}_VERSION_DIR}") - - if (result OR (_PVC_EXACT AND NOT version VERSION_EQUAL expected_version) OR (version VERSION_LESS expected_version)) - # Compiler not usable or has wrong version - if (result) - set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Cannot use the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"") - else() - set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"") - endif() - set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND") - endif() -endfunction() - - -function (_PYTHON_VALIDATE_LIBRARY) - if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE) - unset (_${_PYTHON_PREFIX}_LIBRARY_DEBUG) - return() - endif() - - cmake_parse_arguments (PARSE_ARGV 0 _PVL "EXACT;CHECK_EXISTS" "" "") - if (_PVL_UNPARSED_ARGUMENTS) - set (expected_version ${_PVL_UNPARSED_ARGUMENTS}) - else() - unset (expected_version) - endif() - - if (_PVL_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}") - # library does not exist anymore - set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Cannot find the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"") - set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND") - if (WIN32) - set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_DEBUG PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_DEBUG-NOTFOUND") - endif() - set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND") - return() - endif() - - # retrieve version and abi from library name - _python_get_version (LIBRARY PREFIX lib_) - - if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT lib_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS) - # incompatible ABI - set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong ABI for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"") - set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND") - else() - if (expected_version) - if ((_PVL_EXACT AND NOT lib_VERSION VERSION_EQUAL expected_version) OR (lib_VERSION VERSION_LESS expected_version)) - # library has wrong version - set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"") - set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND") - endif() - else() - if (NOT lib_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) - # library has wrong major version - set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong major version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"") - set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND") - endif() - endif() - endif() - - if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE) - if (WIN32) - set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_DEBUG PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_DEBUG-NOTFOUND") - endif() - unset (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE CACHE) - unset (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG CACHE) - set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND") - endif() -endfunction() - - -function (_PYTHON_VALIDATE_INCLUDE_DIR) - if (NOT _${_PYTHON_PREFIX}_INCLUDE_DIR) - return() - endif() - - cmake_parse_arguments (PARSE_ARGV 0 _PVID "EXACT;CHECK_EXISTS" "" "") - if (_PVID_UNPARSED_ARGUMENTS) - set (expected_version ${_PVID_UNPARSED_ARGUMENTS}) - else() - unset (expected_version) - endif() - - if (_PVID_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}") - # include file does not exist anymore - set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Cannot find the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"") - set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND") - return() - endif() - - # retrieve version from header file - _python_get_version (INCLUDE PREFIX inc_) - - if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT inc_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS) - # incompatible ABI - set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong ABI for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"") - set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND") - else() - if (expected_version) - if ((_PVID_EXACT AND NOT inc_VERSION VERSION_EQUAL expected_version) OR (inc_VERSION VERSION_LESS expected_version)) - # include dir has wrong version - set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"") - set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND") - endif() - else() - if (NOT inc_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) - # include dir has wrong major version - set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong major version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"") - set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND") - endif() - endif() - endif() -endfunction() - - -function (_PYTHON_FIND_RUNTIME_LIBRARY _PYTHON_LIB) - string (REPLACE "_RUNTIME" "" _PYTHON_LIB "${_PYTHON_LIB}") - # look at runtime part on systems supporting it - if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR - (CMAKE_SYSTEM_NAME MATCHES "MSYS|CYGWIN" - AND ${_PYTHON_LIB} MATCHES "${CMAKE_IMPORT_LIBRARY_SUFFIX}$")) - set (CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_SHARED_LIBRARY_SUFFIX}) - # MSYS has a special syntax for runtime libraries - if (CMAKE_SYSTEM_NAME MATCHES "MSYS") - list (APPEND CMAKE_FIND_LIBRARY_PREFIXES "msys-") - endif() - find_library (${ARGV}) - endif() -endfunction() - - -function (_PYTHON_SET_LIBRARY_DIRS _PYTHON_SLD_RESULT) - unset (_PYTHON_DIRS) - set (_PYTHON_LIBS ${ARGN}) - foreach (_PYTHON_LIB IN LISTS _PYTHON_LIBS) - if (${_PYTHON_LIB}) - get_filename_component (_PYTHON_DIR "${${_PYTHON_LIB}}" DIRECTORY) - list (APPEND _PYTHON_DIRS "${_PYTHON_DIR}") - endif() - endforeach() - list (REMOVE_DUPLICATES _PYTHON_DIRS) - set (${_PYTHON_SLD_RESULT} ${_PYTHON_DIRS} PARENT_SCOPE) -endfunction() - - -function (_PYTHON_SET_DEVELOPMENT_MODULE_FOUND module) - if ("Development.${module}" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) - string(TOUPPER "${module}" id) - set (module_found TRUE) - - if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS - AND NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE) - set (module_found FALSE) - endif() - if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS - AND NOT _${_PYTHON_PREFIX}_INCLUDE_DIR) - set (module_found FALSE) - endif() - - set (${_PYTHON_PREFIX}_Development.${module}_FOUND ${module_found} PARENT_SCOPE) - endif() -endfunction() - - -# If major version is specified, it must be the same as internal major version -if (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION_MAJOR - AND NOT ${_PYTHON_PREFIX}_FIND_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) - _python_display_failure ("Could NOT find ${_PYTHON_PREFIX}: Wrong major version specified is \"${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}\", but expected major version is \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\"") -endif() - - -# handle components -if (NOT ${_PYTHON_PREFIX}_FIND_COMPONENTS) - set (${_PYTHON_PREFIX}_FIND_COMPONENTS Interpreter) - set (${_PYTHON_PREFIX}_FIND_REQUIRED_Interpreter TRUE) -endif() -if ("NumPy" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) - list (APPEND ${_PYTHON_PREFIX}_FIND_COMPONENTS "Interpreter" "Development.Module") -endif() -if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) - list (APPEND ${_PYTHON_PREFIX}_FIND_COMPONENTS "Development.Module" "Development.Embed") -endif() -list (REMOVE_DUPLICATES ${_PYTHON_PREFIX}_FIND_COMPONENTS) -foreach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Interpreter Compiler Development Development.Module Development.Embed NumPy) - set (${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_FOUND FALSE) -endforeach() -if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development) - set (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Module TRUE) - set (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Embed TRUE) -endif() - -unset (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) -unset (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS) -unset (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS) -if ("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) - if (CMAKE_SYSTEM_NAME MATCHES "^(Windows.*|CYGWIN|MSYS)$") - list (APPEND _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS "LIBRARY") - endif() - list (APPEND _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS "INCLUDE_DIR") -endif() -if ("Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) - list (APPEND _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS "LIBRARY" "INCLUDE_DIR") -endif() -set (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS ${_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS} ${_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS}) -list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) - -unset (_${_PYTHON_PREFIX}_FIND_VERSIONS) - -# Set versions to search -## default: search any version -set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSIONS}) - -if (${_PYTHON_PREFIX}_FIND_VERSION_COUNT GREATER "1") - if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT) - set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}.${${_PYTHON_PREFIX}_FIND_VERSION_MINOR}) - else() - unset (_${_PYTHON_PREFIX}_FIND_VERSIONS) - # add all compatible versions - foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_VERSIONS) - if (_${_PYTHON_PREFIX}_VERSION VERSION_GREATER_EQUAL ${_PYTHON_PREFIX}_FIND_VERSION) - list (APPEND _${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSION}) - endif() - endforeach() - endif() -endif() - -# Set ABIs to search -## default: search any ABI -if (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR VERSION_LESS "3") - # ABI not supported - unset (_${_PYTHON_PREFIX}_FIND_ABI) - set (_${_PYTHON_PREFIX}_ABIFLAGS "") -else() - unset (_${_PYTHON_PREFIX}_FIND_ABI) - unset (_${_PYTHON_PREFIX}_ABIFLAGS) - if (DEFINED ${_PYTHON_PREFIX}_FIND_ABI) - # normalization - string (TOUPPER "${${_PYTHON_PREFIX}_FIND_ABI}" _${_PYTHON_PREFIX}_FIND_ABI) - list (TRANSFORM _${_PYTHON_PREFIX}_FIND_ABI REPLACE "^(TRUE|Y(ES)?|1)$" "ON") - list (TRANSFORM _${_PYTHON_PREFIX}_FIND_ABI REPLACE "^(FALSE|N(O)?|0)$" "OFF") - if (NOT _${_PYTHON_PREFIX}_FIND_ABI MATCHES "^(ON|OFF|ANY);(ON|OFF|ANY);(ON|OFF|ANY)$") - message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_ABI}: invalid value for '${_PYTHON_PREFIX}_FIND_ABI'. Ignore it") - unset (_${_PYTHON_PREFIX}_FIND_ABI) - endif() - _python_get_abiflags (_${_PYTHON_PREFIX}_ABIFLAGS) - endif() -endif() -unset (${_PYTHON_PREFIX}_SOABI) - -# Define lookup strategy -if (_${_PYTHON_PREFIX}_LOOKUP_POLICY STREQUAL "NEW") - set (_${_PYTHON_PREFIX}_FIND_STRATEGY "LOCATION") -else() - set (_${_PYTHON_PREFIX}_FIND_STRATEGY "VERSION") -endif() -if (DEFINED ${_PYTHON_PREFIX}_FIND_STRATEGY) - if (NOT ${_PYTHON_PREFIX}_FIND_STRATEGY MATCHES "^(VERSION|LOCATION)$") - message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_STRATEGY}: invalid value for '${_PYTHON_PREFIX}_FIND_STRATEGY'. 'VERSION' or 'LOCATION' expected.") - set (_${_PYTHON_PREFIX}_FIND_STRATEGY "VERSION") - else() - set (_${_PYTHON_PREFIX}_FIND_STRATEGY "${${_PYTHON_PREFIX}_FIND_STRATEGY}") - endif() -endif() - -# Python and Anaconda distributions: define which architectures can be used -if (CMAKE_SIZEOF_VOID_P) - # In this case, search only for 64bit or 32bit - math (EXPR _${_PYTHON_PREFIX}_ARCH "${CMAKE_SIZEOF_VOID_P} * 8") - set (_${_PYTHON_PREFIX}_ARCH2 ${_${_PYTHON_PREFIX}_ARCH}) -else() - # architecture unknown, search for both 64bit and 32bit - set (_${_PYTHON_PREFIX}_ARCH 64) - set (_${_PYTHON_PREFIX}_ARCH2 32) -endif() - -# IronPython support -if (CMAKE_SIZEOF_VOID_P) - # In this case, search only for 64bit or 32bit - math (EXPR _${_PYTHON_PREFIX}_ARCH "${CMAKE_SIZEOF_VOID_P} * 8") - set (_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES ipy${_${_PYTHON_PREFIX}_ARCH} ipy) -else() - # architecture unknown, search for natural interpreter - set (_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES ipy) -endif() -set (_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES net45 net40) - -# Apple frameworks handling -_python_find_frameworks () - -set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK "FIRST") - -if (DEFINED ${_PYTHON_PREFIX}_FIND_FRAMEWORK) - if (NOT ${_PYTHON_PREFIX}_FIND_FRAMEWORK MATCHES "^(FIRST|LAST|NEVER)$") - message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_FRAMEWORK}: invalid value for '${_PYTHON_PREFIX}_FIND_FRAMEWORK'. 'FIRST', 'LAST' or 'NEVER' expected. 'FIRST' will be used instead.") - else() - set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK ${${_PYTHON_PREFIX}_FIND_FRAMEWORK}) - endif() -elseif (DEFINED CMAKE_FIND_FRAMEWORK) - if (CMAKE_FIND_FRAMEWORK STREQUAL "ONLY") - message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: CMAKE_FIND_FRAMEWORK: 'ONLY' value is not supported. 'FIRST' will be used instead.") - elseif (NOT CMAKE_FIND_FRAMEWORK MATCHES "^(FIRST|LAST|NEVER)$") - message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${CMAKE_FIND_FRAMEWORK}: invalid value for 'CMAKE_FIND_FRAMEWORK'. 'FIRST', 'LAST' or 'NEVER' expected. 'FIRST' will be used instead.") - else() - set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK}) - endif() -endif() - -# Save CMAKE_FIND_APPBUNDLE -if (DEFINED CMAKE_FIND_APPBUNDLE) - set (_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE ${CMAKE_FIND_APPBUNDLE}) -else() - unset (_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE) -endif() -# To avoid app bundle lookup -set (CMAKE_FIND_APPBUNDLE "NEVER") - -# Save CMAKE_FIND_FRAMEWORK -if (DEFINED CMAKE_FIND_FRAMEWORK) - set (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK}) -else() - unset (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK) -endif() -# To avoid framework lookup -set (CMAKE_FIND_FRAMEWORK "NEVER") - -# Windows Registry handling -if (DEFINED ${_PYTHON_PREFIX}_FIND_REGISTRY) - if (NOT ${_PYTHON_PREFIX}_FIND_REGISTRY MATCHES "^(FIRST|LAST|NEVER)$") - message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_REGISTRY}: invalid value for '${_PYTHON_PREFIX}_FIND_REGISTRY'. 'FIRST', 'LAST' or 'NEVER' expected. 'FIRST' will be used instead.") - set (_${_PYTHON_PREFIX}_FIND_REGISTRY "FIRST") - else() - set (_${_PYTHON_PREFIX}_FIND_REGISTRY ${${_PYTHON_PREFIX}_FIND_REGISTRY}) - endif() -else() - set (_${_PYTHON_PREFIX}_FIND_REGISTRY "FIRST") -endif() - -# virtual environments recognition -if (DEFINED ENV{VIRTUAL_ENV} OR DEFINED ENV{CONDA_PREFIX}) - if (DEFINED ${_PYTHON_PREFIX}_FIND_VIRTUALENV) - if (NOT ${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY|STANDARD)$") - message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_VIRTUALENV}: invalid value for '${_PYTHON_PREFIX}_FIND_VIRTUALENV'. 'FIRST', 'ONLY' or 'STANDARD' expected. 'FIRST' will be used instead.") - set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV "FIRST") - else() - set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV ${${_PYTHON_PREFIX}_FIND_VIRTUALENV}) - endif() - else() - set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV FIRST) - endif() -else() - set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STANDARD) -endif() - - -# Compute search signature -# This signature will be used to check validity of cached variables on new search -set (_${_PYTHON_PREFIX}_SIGNATURE "${${_PYTHON_PREFIX}_ROOT_DIR}:${_${_PYTHON_PREFIX}_FIND_STRATEGY}:${${_PYTHON_PREFIX}_FIND_VIRTUALENV}") -if (NOT WIN32) - string (APPEND _${_PYTHON_PREFIX}_SIGNATURE ":${${_PYTHON_PREFIX}_USE_STATIC_LIBS}:") -endif() -if (CMAKE_HOST_APPLE) - string (APPEND _${_PYTHON_PREFIX}_SIGNATURE ":${_${_PYTHON_PREFIX}_FIND_FRAMEWORK}") -endif() -if (CMAKE_HOST_WIN32) - string (APPEND _${_PYTHON_PREFIX}_SIGNATURE ":${_${_PYTHON_PREFIX}_FIND_REGISTRY}") -endif() - -function (_PYTHON_CHECK_DEVELOPMENT_SIGNATURE module) - if ("Development.${module}" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) - string (TOUPPER "${module}" id) - set (signature "${_${_PYTHON_PREFIX}_SIGNATURE}:") - if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS) - list (APPEND signature "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}:") - endif() - if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS) - list (APPEND signature "${_${_PYTHON_PREFIX}_INCLUDE_DIR}:") - endif() - string (MD5 signature "${signature}") - if (signature STREQUAL _${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE) - if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT) - set (exact EXACT) - endif() - if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS) - _python_validate_library (${${_PYTHON_PREFIX}_FIND_VERSION} ${exact} CHECK_EXISTS) - endif() - if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS) - _python_validate_include_dir (${${_PYTHON_PREFIX}_FIND_VERSION} ${exact} CHECK_EXISTS) - endif() - else() - if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS) - unset (_${_PYTHON_PREFIX}_LIBRARY_RELEASE CACHE) - unset (_${_PYTHON_PREFIX}_LIBRARY_DEBUG CACHE) - endif() - if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS) - unset (_${_PYTHON_PREFIX}_INCLUDE_DIR CACHE) - endif() - endif() - if (("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS - AND NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE) - OR ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS - AND NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)) - unset (_${_PYTHON_PREFIX}_CONFIG CACHE) - unset (_${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE CACHE) - endif() - endif() -endfunction() - -function (_PYTHON_COMPUTE_DEVELOPMENT_SIGNATURE module) - string (TOUPPER "${module}" id) - if (${_PYTHON_PREFIX}_Development.${module}_FOUND) - set (signature "${_${_PYTHON_PREFIX}_SIGNATURE}:") - if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS) - list (APPEND signature "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}:") - endif() - if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS) - list (APPEND signature "${_${_PYTHON_PREFIX}_INCLUDE_DIR}:") - endif() - string (MD5 signature "${signature}") - set (_${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE "${signature}" CACHE INTERNAL "") - else() - unset (_${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE CACHE) - endif() -endfunction() - - -unset (_${_PYTHON_PREFIX}_REQUIRED_VARS) -unset (_${_PYTHON_PREFIX}_CACHED_VARS) -unset (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE) -unset (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE) -unset (_${_PYTHON_PREFIX}_Development_REASON_FAILURE) -unset (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE) - - -# first step, search for the interpreter -if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) - list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_EXECUTABLE) - if (${_PYTHON_PREFIX}_FIND_REQUIRED_Interpreter) - list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_EXECUTABLE) - endif() - - if (DEFINED ${_PYTHON_PREFIX}_EXECUTABLE - AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_EXECUTABLE}") - if (NOT ${_PYTHON_PREFIX}_EXECUTABLE STREQUAL _${_PYTHON_PREFIX}_EXECUTABLE) - # invalidate cache properties - unset (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES CACHE) - endif() - set (_${_PYTHON_PREFIX}_EXECUTABLE "${${_PYTHON_PREFIX}_EXECUTABLE}" CACHE INTERNAL "") - elseif (DEFINED _${_PYTHON_PREFIX}_EXECUTABLE) - # compute interpreter signature and check validity of definition - string (MD5 __${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_EXECUTABLE}") - if (__${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE STREQUAL _${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE) - # check version validity - if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT) - _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS) - else() - _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS) - endif() - else() - unset (_${_PYTHON_PREFIX}_EXECUTABLE CACHE) - endif() - if (NOT _${_PYTHON_PREFIX}_EXECUTABLE) - unset (_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE CACHE) - unset (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES CACHE) - endif() - endif() - - if (NOT _${_PYTHON_PREFIX}_EXECUTABLE) - set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR) - - if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION") - unset (_${_PYTHON_PREFIX}_NAMES) - unset (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS) - unset (_${_PYTHON_PREFIX}_REGISTRY_PATHS) - - foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS) - # build all executable names - _python_get_names (_${_PYTHON_PREFIX}_VERSION_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} POSIX EXECUTABLE) - list (APPEND _${_PYTHON_PREFIX}_NAMES ${_${_PYTHON_PREFIX}_VERSION_NAMES}) - - # Framework Paths - _python_get_frameworks (_${_PYTHON_PREFIX}_VERSION_PATHS ${_${_PYTHON_PREFIX}_VERSION}) - list (APPEND _${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION_PATHS}) - - # Registry Paths - _python_get_registries (_${_PYTHON_PREFIX}_VERSION_PATHS ${_${_PYTHON_PREFIX}_VERSION}) - list (APPEND _${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_VERSION_PATHS} - [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]) - endforeach() - list (APPEND _${_PYTHON_PREFIX}_NAMES python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} python) - - while (TRUE) - # Virtual environments handling - if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$") - find_program (_${_PYTHON_PREFIX}_EXECUTABLE - NAMES ${_${_PYTHON_PREFIX}_NAMES} - NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX - PATH_SUFFIXES bin Scripts - NO_CMAKE_PATH - NO_CMAKE_ENVIRONMENT_PATH - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - - _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION}) - if (_${_PYTHON_PREFIX}_EXECUTABLE) - break() - endif() - if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY") - break() - endif() - endif() - - # Apple frameworks handling - if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") - find_program (_${_PYTHON_PREFIX}_EXECUTABLE - NAMES ${_${_PYTHON_PREFIX}_NAMES} - NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} - PATH_SUFFIXES bin - NO_CMAKE_PATH - NO_CMAKE_ENVIRONMENT_PATH - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION}) - if (_${_PYTHON_PREFIX}_EXECUTABLE) - break() - endif() - endif() - # Windows registry - if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") - find_program (_${_PYTHON_PREFIX}_EXECUTABLE - NAMES ${_${_PYTHON_PREFIX}_NAMES} - ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES} - NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} - PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION}) - if (_${_PYTHON_PREFIX}_EXECUTABLE) - break() - endif() - endif() - - # try using HINTS - find_program (_${_PYTHON_PREFIX}_EXECUTABLE - NAMES ${_${_PYTHON_PREFIX}_NAMES} - ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES} - NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION}) - if (_${_PYTHON_PREFIX}_EXECUTABLE) - break() - endif() - # try using standard paths - find_program (_${_PYTHON_PREFIX}_EXECUTABLE - NAMES ${_${_PYTHON_PREFIX}_NAMES} - ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES} - NAMES_PER_DIR - PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}) - _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION}) - if (_${_PYTHON_PREFIX}_EXECUTABLE) - break() - endif() - - # Apple frameworks handling - if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST") - find_program (_${_PYTHON_PREFIX}_EXECUTABLE - NAMES ${_${_PYTHON_PREFIX}_NAMES} - NAMES_PER_DIR - PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} - PATH_SUFFIXES bin - NO_DEFAULT_PATH) - _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION}) - if (_${_PYTHON_PREFIX}_EXECUTABLE) - break() - endif() - endif() - # Windows registry - if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST") - find_program (_${_PYTHON_PREFIX}_EXECUTABLE - NAMES ${_${_PYTHON_PREFIX}_NAMES} - ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES} - NAMES_PER_DIR - PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} - PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} - NO_DEFAULT_PATH) - _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION}) - if (_${_PYTHON_PREFIX}_EXECUTABLE) - break() - endif() - endif() - - break() - endwhile() - else() - # look-up for various versions and locations - foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS) - _python_get_names (_${_PYTHON_PREFIX}_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} POSIX EXECUTABLE) - list (APPEND _${_PYTHON_PREFIX}_NAMES python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} - python) - - _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION}) - _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_VERSION}) - - # Virtual environments handling - if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$") - find_program (_${_PYTHON_PREFIX}_EXECUTABLE - NAMES ${_${_PYTHON_PREFIX}_NAMES} - NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX - PATH_SUFFIXES bin Scripts - NO_CMAKE_PATH - NO_CMAKE_ENVIRONMENT_PATH - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT) - if (_${_PYTHON_PREFIX}_EXECUTABLE) - break() - endif() - if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY") - continue() - endif() - endif() - - # Apple frameworks handling - if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") - find_program (_${_PYTHON_PREFIX}_EXECUTABLE - NAMES ${_${_PYTHON_PREFIX}_NAMES} - NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} - PATH_SUFFIXES bin - NO_CMAKE_PATH - NO_CMAKE_ENVIRONMENT_PATH - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - endif() - - # Windows registry - if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") - find_program (_${_PYTHON_PREFIX}_EXECUTABLE - NAMES ${_${_PYTHON_PREFIX}_NAMES} - ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES} - NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} - [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] - PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - endif() - - _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT) - if (_${_PYTHON_PREFIX}_EXECUTABLE) - break() - endif() - - # try using HINTS - find_program (_${_PYTHON_PREFIX}_EXECUTABLE - NAMES ${_${_PYTHON_PREFIX}_NAMES} - ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES} - NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT) - if (_${_PYTHON_PREFIX}_EXECUTABLE) - break() - endif() - # try using standard paths. - # NAMES_PER_DIR is not defined on purpose to have a chance to find - # expected version. - # For example, typical systems have 'python' for version 2.* and 'python3' - # for version 3.*. So looking for names per dir will find, potentially, - # systematically 'python' (i.e. version 2) even if version 3 is searched. - if (CMAKE_HOST_WIN32) - find_program (_${_PYTHON_PREFIX}_EXECUTABLE - NAMES ${_${_PYTHON_PREFIX}_NAMES} - python - ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}) - else() - find_program (_${_PYTHON_PREFIX}_EXECUTABLE - NAMES ${_${_PYTHON_PREFIX}_NAMES}) - endif() - _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT) - if (_${_PYTHON_PREFIX}_EXECUTABLE) - break() - endif() - - # Apple frameworks handling - if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST") - find_program (_${_PYTHON_PREFIX}_EXECUTABLE - NAMES ${_${_PYTHON_PREFIX}_NAMES} - NAMES_PER_DIR - PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} - PATH_SUFFIXES bin - NO_DEFAULT_PATH) - endif() - - # Windows registry - if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST") - find_program (_${_PYTHON_PREFIX}_EXECUTABLE - NAMES ${_${_PYTHON_PREFIX}_NAMES} - ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES} - NAMES_PER_DIR - PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} - [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] - PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} - NO_DEFAULT_PATH) - endif() - - _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT) - if (_${_PYTHON_PREFIX}_EXECUTABLE) - break() - endif() - endforeach() - - if (NOT _${_PYTHON_PREFIX}_EXECUTABLE AND - NOT _${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY") - # No specific version found. Retry with generic names and standard paths. - # NAMES_PER_DIR is not defined on purpose to have a chance to find - # expected version. - # For example, typical systems have 'python' for version 2.* and 'python3' - # for version 3.*. So looking for names per dir will find, potentially, - # systematically 'python' (i.e. version 2) even if version 3 is searched. - find_program (_${_PYTHON_PREFIX}_EXECUTABLE - NAMES python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} - python - ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}) - _python_validate_interpreter () - endif() - endif() - endif() - - set (${_PYTHON_PREFIX}_EXECUTABLE "${_${_PYTHON_PREFIX}_EXECUTABLE}") - - # retrieve exact version of executable found - if (_${_PYTHON_PREFIX}_EXECUTABLE) - execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c - "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))" - RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT - OUTPUT_VARIABLE ${_PYTHON_PREFIX}_VERSION - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if (NOT _${_PYTHON_PREFIX}_RESULT) - set (_${_PYTHON_PREFIX}_EXECUTABLE_USABLE TRUE) - else() - # Interpreter is not usable - set (_${_PYTHON_PREFIX}_EXECUTABLE_USABLE FALSE) - unset (${_PYTHON_PREFIX}_VERSION) - set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot run the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"") - endif() - endif() - - if (_${_PYTHON_PREFIX}_EXECUTABLE AND _${_PYTHON_PREFIX}_EXECUTABLE_USABLE) - if (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES) - set (${_PYTHON_PREFIX}_Interpreter_FOUND TRUE) - - list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 0 ${_PYTHON_PREFIX}_INTERPRETER_ID) - - list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 1 ${_PYTHON_PREFIX}_VERSION_MAJOR) - list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 2 ${_PYTHON_PREFIX}_VERSION_MINOR) - list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 3 ${_PYTHON_PREFIX}_VERSION_PATCH) - - list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 4 _${_PYTHON_PREFIX}_ARCH) - set (_${_PYTHON_PREFIX}_ARCH2 ${_${_PYTHON_PREFIX}_ARCH}) - - list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 5 _${_PYTHON_PREFIX}_ABIFLAGS) - list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 6 ${_PYTHON_PREFIX}_SOABI) - - list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 7 ${_PYTHON_PREFIX}_STDLIB) - list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 8 ${_PYTHON_PREFIX}_STDARCH) - list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 9 ${_PYTHON_PREFIX}_SITELIB) - list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 10 ${_PYTHON_PREFIX}_SITEARCH) - else() - string (REGEX MATCHALL "[0-9]+" _${_PYTHON_PREFIX}_VERSIONS "${${_PYTHON_PREFIX}_VERSION}") - list (GET _${_PYTHON_PREFIX}_VERSIONS 0 ${_PYTHON_PREFIX}_VERSION_MAJOR) - list (GET _${_PYTHON_PREFIX}_VERSIONS 1 ${_PYTHON_PREFIX}_VERSION_MINOR) - list (GET _${_PYTHON_PREFIX}_VERSIONS 2 ${_PYTHON_PREFIX}_VERSION_PATCH) - - if (${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) - set (${_PYTHON_PREFIX}_Interpreter_FOUND TRUE) - - # Use interpreter version and ABI for future searches to ensure consistency - set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}) - execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; sys.stdout.write(sys.abiflags)" - RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT - OUTPUT_VARIABLE _${_PYTHON_PREFIX}_ABIFLAGS - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if (_${_PYTHON_PREFIX}_RESULT) - # assunme ABI is not supported - set (_${_PYTHON_PREFIX}_ABIFLAGS "") - endif() - endif() - - if (${_PYTHON_PREFIX}_Interpreter_FOUND) - # compute and save interpreter signature - string (MD5 __${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_EXECUTABLE}") - set (_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE "${__${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE}" CACHE INTERNAL "") - - if (NOT CMAKE_SIZEOF_VOID_P) - # determine interpreter architecture - execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; print(sys.maxsize > 2**32)" - RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT - OUTPUT_VARIABLE ${_PYTHON_PREFIX}_IS64BIT - ERROR_VARIABLE ${_PYTHON_PREFIX}_IS64BIT) - if (NOT _${_PYTHON_PREFIX}_RESULT) - if (${_PYTHON_PREFIX}_IS64BIT) - set (_${_PYTHON_PREFIX}_ARCH 64) - set (_${_PYTHON_PREFIX}_ARCH2 64) - else() - set (_${_PYTHON_PREFIX}_ARCH 32) - set (_${_PYTHON_PREFIX}_ARCH2 32) - endif() - endif() - endif() - - # retrieve interpreter identity - execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -V - RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT - OUTPUT_VARIABLE ${_PYTHON_PREFIX}_INTERPRETER_ID - ERROR_VARIABLE ${_PYTHON_PREFIX}_INTERPRETER_ID) - if (NOT _${_PYTHON_PREFIX}_RESULT) - if (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES "Anaconda") - set (${_PYTHON_PREFIX}_INTERPRETER_ID "Anaconda") - elseif (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES "Enthought") - set (${_PYTHON_PREFIX}_INTERPRETER_ID "Canopy") - else() - string (REGEX REPLACE "^([^ ]+).*" "\\1" ${_PYTHON_PREFIX}_INTERPRETER_ID "${${_PYTHON_PREFIX}_INTERPRETER_ID}") - if (${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "Python") - # try to get a more precise ID - execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; print(sys.copyright)" - RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT - OUTPUT_VARIABLE ${_PYTHON_PREFIX}_COPYRIGHT - ERROR_QUIET) - if (${_PYTHON_PREFIX}_COPYRIGHT MATCHES "ActiveState") - set (${_PYTHON_PREFIX}_INTERPRETER_ID "ActivePython") - endif() - endif() - endif() - else() - set (${_PYTHON_PREFIX}_INTERPRETER_ID Python) - endif() - - # retrieve various package installation directories - execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_python_lib(plat_specific=False,standard_lib=True),sysconfig.get_python_lib(plat_specific=True,standard_lib=True),sysconfig.get_python_lib(plat_specific=False,standard_lib=False),sysconfig.get_python_lib(plat_specific=True,standard_lib=False)]))\nexcept Exception:\n import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_path('stdlib'),sysconfig.get_path('platstdlib'),sysconfig.get_path('purelib'),sysconfig.get_path('platlib')]))" - RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT - OUTPUT_VARIABLE _${_PYTHON_PREFIX}_LIBPATHS - ERROR_QUIET) - if (NOT _${_PYTHON_PREFIX}_RESULT) - list (GET _${_PYTHON_PREFIX}_LIBPATHS 0 ${_PYTHON_PREFIX}_STDLIB) - list (GET _${_PYTHON_PREFIX}_LIBPATHS 1 ${_PYTHON_PREFIX}_STDARCH) - list (GET _${_PYTHON_PREFIX}_LIBPATHS 2 ${_PYTHON_PREFIX}_SITELIB) - list (GET _${_PYTHON_PREFIX}_LIBPATHS 3 ${_PYTHON_PREFIX}_SITEARCH) - else() - unset (${_PYTHON_PREFIX}_STDLIB) - unset (${_PYTHON_PREFIX}_STDARCH) - unset (${_PYTHON_PREFIX}_SITELIB) - unset (${_PYTHON_PREFIX}_SITEARCH) - endif() - - if (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR VERSION_GREATER_EQUAL "3") - _python_get_config_var (${_PYTHON_PREFIX}_SOABI SOABI) - endif() - - # store properties in the cache to speed-up future searches - set (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES - "${${_PYTHON_PREFIX}_INTERPRETER_ID};${${_PYTHON_PREFIX}_VERSION_MAJOR};${${_PYTHON_PREFIX}_VERSION_MINOR};${${_PYTHON_PREFIX}_VERSION_PATCH};${_${_PYTHON_PREFIX}_ARCH};${_${_PYTHON_PREFIX}_ABIFLAGS};${${_PYTHON_PREFIX}_SOABI};${${_PYTHON_PREFIX}_STDLIB};${${_PYTHON_PREFIX}_STDARCH};${${_PYTHON_PREFIX}_SITELIB};${${_PYTHON_PREFIX}_SITEARCH}" CACHE INTERNAL "${_PYTHON_PREFIX} Properties") - else() - unset (_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE CACHE) - unset (${_PYTHON_PREFIX}_INTERPRETER_ID) - endif() - endif() - endif() - - if (${_PYTHON_PREFIX}_ARTIFACTS_INTERACTIVE) - set (${_PYTHON_PREFIX}_EXECUTABLE "${_${_PYTHON_PREFIX}_EXECUTABLE}" CACHE FILEPATH "${_PYTHON_PREFIX} Interpreter") - endif() - - _python_mark_as_internal (_${_PYTHON_PREFIX}_EXECUTABLE - _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES - _${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE) -endif() - - -# second step, search for compiler (IronPython) -if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) - list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_COMPILER) - if (${_PYTHON_PREFIX}_FIND_REQUIRED_Compiler) - list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_COMPILER) - endif() - - if (DEFINED ${_PYTHON_PREFIX}_COMPILER - AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_COMPILER}") - set (_${_PYTHON_PREFIX}_COMPILER "${${_PYTHON_PREFIX}_COMPILER}" CACHE INTERNAL "") - elseif (DEFINED _${_PYTHON_PREFIX}_COMPILER) - # compute compiler signature and check validity of definition - string (MD5 __${_PYTHON_PREFIX}_COMPILER_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_COMPILER}") - if (__${_PYTHON_PREFIX}_COMPILER_SIGNATURE STREQUAL _${_PYTHON_PREFIX}_COMPILER_SIGNATURE) - # check version validity - if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT) - _python_validate_compiler (${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS) - else() - _python_validate_compiler (${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS) - endif() - else() - unset (_${_PYTHON_PREFIX}_COMPILER CACHE) - unset (_${_PYTHON_PREFIX}_COMPILER_SIGNATURE CACHE) - endif() - endif() - - if (NOT _${_PYTHON_PREFIX}_COMPILER) - # IronPython specific artifacts - # If IronPython interpreter is found, use its path - unset (_${_PYTHON_PREFIX}_IRON_ROOT) - if (${_PYTHON_PREFIX}_Interpreter_FOUND AND ${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "IronPython") - get_filename_component (_${_PYTHON_PREFIX}_IRON_ROOT "${${_PYTHON_PREFIX}_EXECUTABLE}" DIRECTORY) - endif() - - if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION") - set (_${_PYTHON_PREFIX}_REGISTRY_PATHS) - - foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS) - # Registry Paths - list (APPEND _${_PYTHON_PREFIX}_REGISTRY_PATHS - [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]) - endforeach() - - while (TRUE) - if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") - find_program (_${_PYTHON_PREFIX}_COMPILER - NAMES ipyc - HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} - PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - _python_validate_compiler (${${_PYTHON_PREFIX}_FIND_VERSION}) - if (_${_PYTHON_PREFIX}_COMPILER) - break() - endif() - endif() - - find_program (_${_PYTHON_PREFIX}_COMPILER - NAMES ipyc - HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS} - PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - _python_validate_compiler (${${_PYTHON_PREFIX}_FIND_VERSION}) - if (_${_PYTHON_PREFIX}_COMPILER) - break() - endif() - - if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST") - find_program (_${_PYTHON_PREFIX}_COMPILER - NAMES ipyc - PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} - PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} - NO_DEFAULT_PATH) - endif() - - break() - endwhile() - else() - # try using root dir and registry - foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS) - if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") - find_program (_${_PYTHON_PREFIX}_COMPILER - NAMES ipyc - HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS} - PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] - PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - _python_validate_compiler (${_${_PYTHON_PREFIX}_VERSION} EXACT) - if (_${_PYTHON_PREFIX}_COMPILER) - break() - endif() - endif() - - find_program (_${_PYTHON_PREFIX}_COMPILER - NAMES ipyc - HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS} - PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - _python_validate_compiler (${_${_PYTHON_PREFIX}_VERSION} EXACT) - if (_${_PYTHON_PREFIX}_COMPILER) - break() - endif() - - if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST") - find_program (_${_PYTHON_PREFIX}_COMPILER - NAMES ipyc - PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] - PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} - NO_DEFAULT_PATH) - _python_validate_compiler (${_${_PYTHON_PREFIX}_VERSION} EXACT) - if (_${_PYTHON_PREFIX}_COMPILER) - break() - endif() - endif() - endforeach() - - # no specific version found, re-try in standard paths - find_program (_${_PYTHON_PREFIX}_COMPILER - NAMES ipyc - HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS} - PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}) - endif() - endif() - - set (${_PYTHON_PREFIX}_COMPILER "${_${_PYTHON_PREFIX}_COMPILER}") - - if (_${_PYTHON_PREFIX}_COMPILER) - # retrieve python environment version from compiler - set (_${_PYTHON_PREFIX}_VERSION_DIR "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/PythonCompilerVersion.dir") - file (WRITE "${_${_PYTHON_PREFIX}_VERSION_DIR}/version.py" "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))\n") - execute_process (COMMAND "${_${_PYTHON_PREFIX}_COMPILER}" /target:exe /embed "${_${_PYTHON_PREFIX}_VERSION_DIR}/version.py" - WORKING_DIRECTORY "${_${_PYTHON_PREFIX}_VERSION_DIR}" - OUTPUT_QUIET - ERROR_QUIET) - execute_process (COMMAND "${_${_PYTHON_PREFIX}_VERSION_DIR}/version" - WORKING_DIRECTORY "${_${_PYTHON_PREFIX}_VERSION_DIR}" - RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT - OUTPUT_VARIABLE _${_PYTHON_PREFIX}_VERSION - ERROR_QUIET) - if (NOT _${_PYTHON_PREFIX}_RESULT) - set (_${_PYTHON_PREFIX}_COMPILER_USABLE TRUE) - string (REGEX MATCHALL "[0-9]+" _${_PYTHON_PREFIX}_VERSIONS "${_${_PYTHON_PREFIX}_VERSION}") - list (GET _${_PYTHON_PREFIX}_VERSIONS 0 _${_PYTHON_PREFIX}_VERSION_MAJOR) - list (GET _${_PYTHON_PREFIX}_VERSIONS 1 _${_PYTHON_PREFIX}_VERSION_MINOR) - list (GET _${_PYTHON_PREFIX}_VERSIONS 2 _${_PYTHON_PREFIX}_VERSION_PATCH) - - if (NOT ${_PYTHON_PREFIX}_Interpreter_FOUND) - # set public version information - set (${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_VERSION}) - set (${_PYTHON_PREFIX}_VERSION_MAJOR ${_${_PYTHON_PREFIX}_VERSION_MAJOR}) - set (${_PYTHON_PREFIX}_VERSION_MINOR ${_${_PYTHON_PREFIX}_VERSION_MINOR}) - set (${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_VERSION_PATCH}) - endif() - else() - # compiler not usable - set (_${_PYTHON_PREFIX}_COMPILER_USABLE FALSE) - set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Cannot run the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"") - endif() - file (REMOVE_RECURSE "${_${_PYTHON_PREFIX}_VERSION_DIR}") - endif() - - if (_${_PYTHON_PREFIX}_COMPILER AND _${_PYTHON_PREFIX}_COMPILER_USABLE) - if (${_PYTHON_PREFIX}_Interpreter_FOUND) - # Compiler must be compatible with interpreter - if ("${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}" VERSION_EQUAL "${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}") - set (${_PYTHON_PREFIX}_Compiler_FOUND TRUE) - endif() - elseif (${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) - set (${_PYTHON_PREFIX}_Compiler_FOUND TRUE) - # Use compiler version for future searches to ensure consistency - set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}) - endif() - endif() - - if (${_PYTHON_PREFIX}_Compiler_FOUND) - # compute and save compiler signature - string (MD5 __${_PYTHON_PREFIX}_COMPILER_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_COMPILER}") - set (_${_PYTHON_PREFIX}_COMPILER_SIGNATURE "${__${_PYTHON_PREFIX}_COMPILER_SIGNATURE}" CACHE INTERNAL "") - - set (${_PYTHON_PREFIX}_COMPILER_ID IronPython) - else() - unset (_${_PYTHON_PREFIX}_COMPILER_SIGNATURE CACHE) - unset (${_PYTHON_PREFIX}_COMPILER_ID) - endif() - - if (${_PYTHON_PREFIX}_ARTIFACTS_INTERACTIVE) - set (${_PYTHON_PREFIX}_COMPILER "${_${_PYTHON_PREFIX}_COMPILER}" CACHE FILEPATH "${_PYTHON_PREFIX} Compiler") - endif() - - _python_mark_as_internal (_${_PYTHON_PREFIX}_COMPILER - _${_PYTHON_PREFIX}_COMPILER_SIGNATURE) -endif() - - -# third step, search for the development artifacts -## Development environment is not compatible with IronPython interpreter -if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS - OR "Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) - AND NOT ${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "IronPython") - if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) - list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_LIBRARY_RELEASE - _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE - _${_PYTHON_PREFIX}_LIBRARY_DEBUG - _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG) - endif() - if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) - list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_INCLUDE_DIR) - endif() - if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Module) - if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS) - list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_LIBRARIES) - endif() - if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS) - list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_INCLUDE_DIRS) - endif() - endif() - if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Embed) - if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS) - list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_LIBRARIES) - endif() - if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS) - list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_INCLUDE_DIRS) - endif() - endif() - list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_REQUIRED_VARS) - - _python_check_development_signature (Module) - _python_check_development_signature (Embed) - - if (DEFINED ${_PYTHON_PREFIX}_LIBRARY - AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_LIBRARY}") - set (_${_PYTHON_PREFIX}_LIBRARY_RELEASE "${${_PYTHON_PREFIX}_LIBRARY}" CACHE INTERNAL "") - unset (_${_PYTHON_PREFIX}_LIBRARY_DEBUG CACHE) - unset (_${_PYTHON_PREFIX}_INCLUDE_DIR CACHE) - endif() - if (DEFINED ${_PYTHON_PREFIX}_INCLUDE_DIR - AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_INCLUDE_DIR}") - set (_${_PYTHON_PREFIX}_INCLUDE_DIR "${${_PYTHON_PREFIX}_INCLUDE_DIR}" CACHE INTERNAL "") - endif() - - # Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES - unset (_${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES) - if (DEFINED ${_PYTHON_PREFIX}_USE_STATIC_LIBS AND NOT WIN32) - set(_${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) - if(${_PYTHON_PREFIX}_USE_STATIC_LIBS) - set (CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX}) - else() - list (REMOVE_ITEM CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX}) - endif() - endif() - - if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE OR NOT _${_PYTHON_PREFIX}_INCLUDE_DIR) - # if python interpreter is found, use it to look-up for artifacts - # to ensure consistency between interpreter and development environments. - # If not, try to locate a compatible config tool - if (NOT ${_PYTHON_PREFIX}_Interpreter_FOUND OR CMAKE_CROSSCOMPILING) - set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR) - unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS) - if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$") - set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX) - endif() - unset (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS) - - if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION") - set (_${_PYTHON_PREFIX}_CONFIG_NAMES) - - foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS) - _python_get_names (_${_PYTHON_PREFIX}_VERSION_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} POSIX CONFIG) - list (APPEND _${_PYTHON_PREFIX}_CONFIG_NAMES ${_${_PYTHON_PREFIX}_VERSION_NAMES}) - - # Framework Paths - _python_get_frameworks (_${_PYTHON_PREFIX}_VERSION_PATHS ${_${_PYTHON_PREFIX}_VERSION}) - list (APPEND _${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION_PATHS}) - endforeach() - - # Apple frameworks handling - if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") - find_program (_${_PYTHON_PREFIX}_CONFIG - NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES} - NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} - ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} - PATH_SUFFIXES bin - NO_CMAKE_PATH - NO_CMAKE_ENVIRONMENT_PATH - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - endif() - - find_program (_${_PYTHON_PREFIX}_CONFIG - NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES} - NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} - PATH_SUFFIXES bin) - - # Apple frameworks handling - if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST") - find_program (_${_PYTHON_PREFIX}_CONFIG - NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES} - NAMES_PER_DIR - PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} - PATH_SUFFIXES bin - NO_DEFAULT_PATH) - endif() - - if (_${_PYTHON_PREFIX}_CONFIG) - execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --help - RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT - OUTPUT_VARIABLE __${_PYTHON_PREFIX}_HELP - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if (_${_PYTHON_PREFIX}_RESULT) - # assume config tool is not usable - unset (_${_PYTHON_PREFIX}_CONFIG CACHE) - endif() - endif() - - if (_${_PYTHON_PREFIX}_CONFIG) - execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --abiflags - RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT - OUTPUT_VARIABLE __${_PYTHON_PREFIX}_ABIFLAGS - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if (_${_PYTHON_PREFIX}_RESULT) - # assume ABI is not supported - set (__${_PYTHON_PREFIX}_ABIFLAGS "") - endif() - if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT __${_PYTHON_PREFIX}_ABIFLAGS IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS) - # Wrong ABI - unset (_${_PYTHON_PREFIX}_CONFIG CACHE) - endif() - endif() - - if (_${_PYTHON_PREFIX}_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE) - # check that config tool match library architecture - execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --configdir - RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT - OUTPUT_VARIABLE _${_PYTHON_PREFIX}_CONFIGDIR - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if (_${_PYTHON_PREFIX}_RESULT) - unset (_${_PYTHON_PREFIX}_CONFIG CACHE) - else() - string(FIND "${_${_PYTHON_PREFIX}_CONFIGDIR}" "${CMAKE_LIBRARY_ARCHITECTURE}" _${_PYTHON_PREFIX}_RESULT) - if (_${_PYTHON_PREFIX}_RESULT EQUAL -1) - unset (_${_PYTHON_PREFIX}_CONFIG CACHE) - endif() - endif() - endif() - else() - foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS) - # try to use pythonX.Y-config tool - _python_get_names (_${_PYTHON_PREFIX}_CONFIG_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} POSIX CONFIG) - - # Framework Paths - _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION}) - - # Apple frameworks handling - if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") - find_program (_${_PYTHON_PREFIX}_CONFIG - NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES} - NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} - ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} - PATH_SUFFIXES bin - NO_CMAKE_PATH - NO_CMAKE_ENVIRONMENT_PATH - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - endif() - - find_program (_${_PYTHON_PREFIX}_CONFIG - NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES} - NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} - PATH_SUFFIXES bin) - - # Apple frameworks handling - if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST") - find_program (_${_PYTHON_PREFIX}_CONFIG - NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES} - NAMES_PER_DIR - PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} - PATH_SUFFIXES bin - NO_DEFAULT_PATH) - endif() - - unset (_${_PYTHON_PREFIX}_CONFIG_NAMES) - - if (_${_PYTHON_PREFIX}_CONFIG) - execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --help - RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT - OUTPUT_VARIABLE __${_PYTHON_PREFIX}_HELP - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if (_${_PYTHON_PREFIX}_RESULT) - # assume config tool is not usable - unset (_${_PYTHON_PREFIX}_CONFIG CACHE) - endif() - endif() - - if (NOT _${_PYTHON_PREFIX}_CONFIG) - continue() - endif() - - execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --abiflags - RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT - OUTPUT_VARIABLE __${_PYTHON_PREFIX}_ABIFLAGS - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if (_${_PYTHON_PREFIX}_RESULT) - # assume ABI is not supported - set (__${_PYTHON_PREFIX}_ABIFLAGS "") - endif() - if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT __${_PYTHON_PREFIX}_ABIFLAGS IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS) - # Wrong ABI - unset (_${_PYTHON_PREFIX}_CONFIG CACHE) - continue() - endif() - - if (_${_PYTHON_PREFIX}_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE) - # check that config tool match library architecture - execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --configdir - RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT - OUTPUT_VARIABLE _${_PYTHON_PREFIX}_CONFIGDIR - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if (_${_PYTHON_PREFIX}_RESULT) - unset (_${_PYTHON_PREFIX}_CONFIG CACHE) - continue() - endif() - string (FIND "${_${_PYTHON_PREFIX}_CONFIGDIR}" "${CMAKE_LIBRARY_ARCHITECTURE}" _${_PYTHON_PREFIX}_RESULT) - if (_${_PYTHON_PREFIX}_RESULT EQUAL -1) - unset (_${_PYTHON_PREFIX}_CONFIG CACHE) - continue() - endif() - endif() - - if (_${_PYTHON_PREFIX}_CONFIG) - break() - endif() - endforeach() - endif() - endif() - endif() - - if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) - if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE) - if ((${_PYTHON_PREFIX}_Interpreter_FOUND AND NOT CMAKE_CROSSCOMPILING) OR _${_PYTHON_PREFIX}_CONFIG) - # retrieve root install directory - _python_get_config_var (_${_PYTHON_PREFIX}_PREFIX PREFIX) - - # enforce current ABI - _python_get_config_var (_${_PYTHON_PREFIX}_ABIFLAGS ABIFLAGS) - - set (_${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_PREFIX}") - - # retrieve library - ## compute some paths and artifact names - if (_${_PYTHON_PREFIX}_CONFIG) - string (REGEX REPLACE "^.+python([0-9.]+)[a-z]*-config" "\\1" _${_PYTHON_PREFIX}_VERSION "${_${_PYTHON_PREFIX}_CONFIG}") - else() - set (_${_PYTHON_PREFIX}_VERSION "${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}") - endif() - _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_VERSION} LIBRARY) - _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} WIN32 POSIX LIBRARY) - - _python_get_config_var (_${_PYTHON_PREFIX}_CONFIGDIR CONFIGDIR) - list (APPEND _${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_CONFIGDIR}") - - list (APPEND _${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR) - - find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE - NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} - NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - endif() - - # Rely on HINTS and standard paths if interpreter or config tool failed to locate artifacts - if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE) - set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR) - - unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS) - if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$") - set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX) - endif() - - if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION") - unset (_${_PYTHON_PREFIX}_LIB_NAMES) - unset (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG) - unset (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS) - unset (_${_PYTHON_PREFIX}_REGISTRY_PATHS) - unset (_${_PYTHON_PREFIX}_PATH_SUFFIXES) - - foreach (_${_PYTHON_PREFIX}_LIB_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS) - # library names - _python_get_names (_${_PYTHON_PREFIX}_VERSION_NAMES VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} WIN32 POSIX LIBRARY) - list (APPEND _${_PYTHON_PREFIX}_LIB_NAMES ${_${_PYTHON_PREFIX}_VERSION_NAMES}) - _python_get_names (_${_PYTHON_PREFIX}_VERSION_NAMES VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} WIN32 DEBUG) - list (APPEND _${_PYTHON_PREFIX}_LIB_NAMES_DEBUG ${_${_PYTHON_PREFIX}_VERSION_NAMES}) - - # Framework Paths - _python_get_frameworks (_${_PYTHON_PREFIX}_VERSION_PATHS ${_${_PYTHON_PREFIX}_LIB_VERSION}) - list (APPEND _${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION_PATHS}) - - # Registry Paths - _python_get_registries (_${_PYTHON_PREFIX}_VERSION_PATHS ${_${_PYTHON_PREFIX}_LIB_VERSION}) - list (APPEND _${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_VERSION_PATHS}) - - # Paths suffixes - _python_get_path_suffixes (_${_PYTHON_PREFIX}_VERSION_PATHS VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} LIBRARY) - list (APPEND _${_PYTHON_PREFIX}_PATH_SUFFIXES ${_${_PYTHON_PREFIX}_VERSION_PATHS}) - endforeach() - - if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") - find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE - NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} - NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} - ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} - PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} - NO_CMAKE_PATH - NO_CMAKE_ENVIRONMENT_PATH - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - endif() - - if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") - find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE - NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} - NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} - ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} - PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - endif() - - # search in HINTS locations - find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE - NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} - NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} - PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - - if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST") - set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}) - else() - unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS) - endif() - - if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST") - set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}) - else() - unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS) - endif() - - # search in all default paths - find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE - NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} - NAMES_PER_DIR - PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS} - ${__${_PYTHON_PREFIX}_REGISTRY_PATHS} - PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}) - else() - foreach (_${_PYTHON_PREFIX}_LIB_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS) - _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} WIN32 POSIX LIBRARY) - _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} WIN32 DEBUG) - - _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_LIB_VERSION}) - _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_LIB_VERSION}) - - _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} LIBRARY) - - if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") - find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE - NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} - NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} - ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} - PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} - NO_CMAKE_PATH - NO_CMAKE_ENVIRONMENT_PATH - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - endif() - - if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") - find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE - NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} - NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} - ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} - PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - endif() - - # search in HINTS locations - find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE - NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} - NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} - PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - - if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST") - set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}) - else() - unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS) - endif() - - if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST") - set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}) - else() - unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS) - endif() - - # search in all default paths - find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE - NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} - NAMES_PER_DIR - PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS} - ${__${_PYTHON_PREFIX}_REGISTRY_PATHS} - PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}) - - if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE) - break() - endif() - endforeach() - endif() - endif() - endif() - - # finalize library version information - _python_get_version (LIBRARY PREFIX _${_PYTHON_PREFIX}_) - - set (${_PYTHON_PREFIX}_LIBRARY_RELEASE "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}") - - if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE AND NOT EXISTS "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}") - set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Cannot find the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"") - set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND") - endif() - - set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR) - - if (WIN32 AND _${_PYTHON_PREFIX}_LIBRARY_RELEASE) - # search for debug library - # use release library location as a hint - _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_VERSION} WIN32 DEBUG) - get_filename_component (_${_PYTHON_PREFIX}_PATH "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY) - find_library (_${_PYTHON_PREFIX}_LIBRARY_DEBUG - NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG} - NAMES_PER_DIR - HINTS "${_${_PYTHON_PREFIX}_PATH}" ${_${_PYTHON_PREFIX}_HINTS} - NO_DEFAULT_PATH) - endif() - - # retrieve runtime libraries - if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE) - _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} WIN32 POSIX LIBRARY) - get_filename_component (_${_PYTHON_PREFIX}_PATH "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY) - get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY) - _python_find_runtime_library (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE - NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} - NAMES_PER_DIR - HINTS "${_${_PYTHON_PREFIX}_PATH}" "${_${_PYTHON_PREFIX}_PATH2}" ${_${_PYTHON_PREFIX}_HINTS} - PATH_SUFFIXES bin) - endif() - if (_${_PYTHON_PREFIX}_LIBRARY_DEBUG) - _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_VERSION} WIN32 DEBUG) - get_filename_component (_${_PYTHON_PREFIX}_PATH "${_${_PYTHON_PREFIX}_LIBRARY_DEBUG}" DIRECTORY) - get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY) - _python_find_runtime_library (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG - NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG} - NAMES_PER_DIR - HINTS "${_${_PYTHON_PREFIX}_PATH}" "${_${_PYTHON_PREFIX}_PATH2}" ${_${_PYTHON_PREFIX}_HINTS} - PATH_SUFFIXES bin) - endif() - endif() - - if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) - while (NOT _${_PYTHON_PREFIX}_INCLUDE_DIR) - if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS - AND NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE) - # Don't search for include dir if no library was founded - break() - endif() - - if ((${_PYTHON_PREFIX}_Interpreter_FOUND AND NOT CMAKE_CROSSCOMPILING) OR _${_PYTHON_PREFIX}_CONFIG) - _python_get_config_var (_${_PYTHON_PREFIX}_INCLUDE_DIRS INCLUDES) - - find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR - NAMES Python.h - HINTS ${_${_PYTHON_PREFIX}_INCLUDE_DIRS} - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - endif() - - # Rely on HINTS and standard paths if interpreter or config tool failed to locate artifacts - if (NOT _${_PYTHON_PREFIX}_INCLUDE_DIR) - unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS) - if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$") - set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX) - endif() - unset (_${_PYTHON_PREFIX}_INCLUDE_HINTS) - - if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE) - # Use the library's install prefix as a hint - if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "^(.+/Frameworks/Python.framework/Versions/[0-9.]+)") - list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}") - elseif (_${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "^(.+)/lib(64|32)?/python[0-9.]+/config") - list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}") - elseif (DEFINED CMAKE_LIBRARY_ARCHITECTURE AND ${_${_PYTHON_PREFIX}_LIBRARY_RELEASE} MATCHES "^(.+)/lib/${CMAKE_LIBRARY_ARCHITECTURE}") - list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}") - else() - # assume library is in a directory under root - get_filename_component (_${_PYTHON_PREFIX}_PREFIX "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY) - get_filename_component (_${_PYTHON_PREFIX}_PREFIX "${_${_PYTHON_PREFIX}_PREFIX}" DIRECTORY) - list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${_${_PYTHON_PREFIX}_PREFIX}") - endif() - endif() - - _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION}) - _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_VERSION}) - _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_VERSION} INCLUDE) - - if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") - find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR - NAMES Python.h - HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} - ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} - PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} - NO_CMAKE_PATH - NO_CMAKE_ENVIRONMENT_PATH - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - endif() - - if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") - find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR - NAMES Python.h - HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} - ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} - PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - endif() - - if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST") - set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}) - else() - unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS) - endif() - - if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST") - set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}) - else() - unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS) - endif() - - find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR - NAMES Python.h - HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} - ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS} - ${__${_PYTHON_PREFIX}_REGISTRY_PATHS} - PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) - endif() - - # search header file in standard locations - find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR - NAMES Python.h) - - break() - endwhile() - - set (${_PYTHON_PREFIX}_INCLUDE_DIRS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}") - - if (_${_PYTHON_PREFIX}_INCLUDE_DIR AND NOT EXISTS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}") - set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Cannot find the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"") - set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND") - endif() - - if (_${_PYTHON_PREFIX}_INCLUDE_DIR) - # retrieve version from header file - _python_get_version (INCLUDE PREFIX _${_PYTHON_PREFIX}_INC_) - - if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE) - # update versioning - if (_${_PYTHON_PREFIX}_INC_VERSION VERSION_EQUAL _${_PYTHON_PREFIX}_VERSION) - set (_${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_INC_VERSION_PATCH}) - endif() - else() - set (_${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_INC_VERSION}) - set (_${_PYTHON_PREFIX}_VERSION_MAJOR ${_${_PYTHON_PREFIX}_INC_VERSION_MAJOR}) - set (_${_PYTHON_PREFIX}_VERSION_MINOR ${_${_PYTHON_PREFIX}_INC_VERSION_MINOR}) - set (_${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_INC_VERSION_PATCH}) - endif() - endif() - endif() - - if (NOT ${_PYTHON_PREFIX}_Interpreter_FOUND AND NOT ${_PYTHON_PREFIX}_Compiler_FOUND) - # set public version information - set (${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_VERSION}) - set (${_PYTHON_PREFIX}_VERSION_MAJOR ${_${_PYTHON_PREFIX}_VERSION_MAJOR}) - set (${_PYTHON_PREFIX}_VERSION_MINOR ${_${_PYTHON_PREFIX}_VERSION_MINOR}) - set (${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_VERSION_PATCH}) - endif() - - # define public variables - if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) - set (${_PYTHON_PREFIX}_LIBRARY_DEBUG "${_${_PYTHON_PREFIX}_LIBRARY_DEBUG}") - _python_select_library_configurations (${_PYTHON_PREFIX}) - - set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE "${_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}") - set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG "${_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG}") - - if (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE) - set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY "${_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}") - elseif (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG) - set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY "${_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG}") - else() - set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY "${_PYTHON_PREFIX}_RUNTIME_LIBRARY-NOTFOUND") - endif() - - _python_set_library_dirs (${_PYTHON_PREFIX}_LIBRARY_DIRS - _${_PYTHON_PREFIX}_LIBRARY_RELEASE _${_PYTHON_PREFIX}_LIBRARY_DEBUG) - if (UNIX) - if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$") - set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DIRS ${${_PYTHON_PREFIX}_LIBRARY_DIRS}) - endif() - else() - _python_set_library_dirs (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DIRS - _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG) - endif() - endif() - - if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE OR _${_PYTHON_PREFIX}_INCLUDE_DIR) - if (${_PYTHON_PREFIX}_Interpreter_FOUND OR ${_PYTHON_PREFIX}_Compiler_FOUND) - # development environment must be compatible with interpreter/compiler - if ("${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}" VERSION_EQUAL "${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}" - AND "${_${_PYTHON_PREFIX}_INC_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_INC_VERSION_MINOR}" VERSION_EQUAL "${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}") - _python_set_development_module_found (Module) - _python_set_development_module_found (Embed) - endif() - elseif (${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR - AND "${_${_PYTHON_PREFIX}_INC_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_INC_VERSION_MINOR}" VERSION_EQUAL "${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}") - _python_set_development_module_found (Module) - _python_set_development_module_found (Embed) - endif() - if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND - (NOT _${_PYTHON_PREFIX}_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS - OR NOT _${_PYTHON_PREFIX}_INC_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)) - set (${_PYTHON_PREFIX}_Development.Module_FOUND FALSE) - set (${_PYTHON_PREFIX}_Development.Embed_FOUND FALSE) - endif() - endif() - - if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS - AND ${_PYTHON_PREFIX}_Development.Module_FOUND - AND ${_PYTHON_PREFIX}_Development.Embed_FOUND) - set (${_PYTHON_PREFIX}_Development_FOUND TRUE) - endif() - - if (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR VERSION_GREATER_EQUAL "3" - AND NOT DEFINED ${_PYTHON_PREFIX}_SOABI) - _python_get_config_var (${_PYTHON_PREFIX}_SOABI SOABI) - endif() - - _python_compute_development_signature (Module) - _python_compute_development_signature (Embed) - - # Restore the original find library ordering - if (DEFINED _${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES) - set (CMAKE_FIND_LIBRARY_SUFFIXES ${_${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES}) - endif() - - if (${_PYTHON_PREFIX}_ARTIFACTS_INTERACTIVE) - if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) - set (${_PYTHON_PREFIX}_LIBRARY "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" CACHE FILEPATH "${_PYTHON_PREFIX} Library") - endif() - if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) - set (${_PYTHON_PREFIX}_INCLUDE_DIR "${_${_PYTHON_PREFIX}_INCLUDE_DIR}" CACHE FILEPATH "${_PYTHON_PREFIX} Include Directory") - endif() - endif() - - _python_mark_as_internal (_${_PYTHON_PREFIX}_LIBRARY_RELEASE - _${_PYTHON_PREFIX}_LIBRARY_DEBUG - _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE - _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG - _${_PYTHON_PREFIX}_INCLUDE_DIR - _${_PYTHON_PREFIX}_CONFIG - _${_PYTHON_PREFIX}_DEVELOPMENT_MODULE_SIGNATURE - _${_PYTHON_PREFIX}_DEVELOPMENT_EMBED_SIGNATURE) -endif() - -if ("NumPy" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_Interpreter_FOUND) - list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR) - if (${_PYTHON_PREFIX}_FIND_REQUIRED_NumPy) - list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_NumPy_INCLUDE_DIRS) - endif() - - if (DEFINED ${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR - AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}") - set (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR "${${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}" CACHE INTERNAL "") - elseif (DEFINED _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR) - # compute numpy signature. Depends on interpreter and development signatures - string (MD5 __${_PYTHON_PREFIX}_NUMPY_SIGNATURE "${_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE}:${_${_PYTHON_PREFIX}_DEVELOPMENT_MODULE_SIGNATURE}:${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}") - if (NOT __${_PYTHON_PREFIX}_NUMPY_SIGNATURE STREQUAL _${_PYTHON_PREFIX}_NUMPY_SIGNATURE - OR NOT EXISTS "${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}") - unset (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR CACHE) - unset (_${_PYTHON_PREFIX}_NUMPY_SIGNATURE CACHE) - endif() - endif() - - if (NOT _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR) - execute_process( - COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c - "from __future__ import print_function\ntry: import numpy; print(numpy.get_include(), end='')\nexcept:pass\n" - RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT - OUTPUT_VARIABLE _${_PYTHON_PREFIX}_NumPy_PATH - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - - if (NOT _${_PYTHON_PREFIX}_RESULT) - find_path (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR - NAMES "numpy/arrayobject.h" "numpy/numpyconfig.h" - HINTS "${_${_PYTHON_PREFIX}_NumPy_PATH}" - NO_DEFAULT_PATH) - endif() - endif() - - set (${_PYTHON_PREFIX}_NumPy_INCLUDE_DIRS "${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}") - - if(_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR AND NOT EXISTS "${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}") - set (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE "Cannot find the directory \"${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}\"") - set_property (CACHE _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR-NOTFOUND") - endif() - - if (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR) - execute_process ( - COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c - "from __future__ import print_function\ntry: import numpy; print(numpy.__version__, end='')\nexcept:pass\n" - RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT - OUTPUT_VARIABLE _${_PYTHON_PREFIX}_NumPy_VERSION) - if (NOT _${_PYTHON_PREFIX}_RESULT) - set (${_PYTHON_PREFIX}_NumPy_VERSION "${_${_PYTHON_PREFIX}_NumPy_VERSION}") - else() - unset (${_PYTHON_PREFIX}_NumPy_VERSION) - endif() - - # final step: set NumPy founded only if Development.Module component is founded as well - set(${_PYTHON_PREFIX}_NumPy_FOUND ${${_PYTHON_PREFIX}_Development.Module_FOUND}) - else() - set (${_PYTHON_PREFIX}_NumPy_FOUND FALSE) - endif() - - if (${_PYTHON_PREFIX}_NumPy_FOUND) - # compute and save numpy signature - string (MD5 __${_PYTHON_PREFIX}_NUMPY_SIGNATURE "${_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE}:${_${_PYTHON_PREFIX}_DEVELOPMENT_MODULE_SIGNATURE}:${${_PYTHON_PREFIX}_NumPyINCLUDE_DIR}") - set (_${_PYTHON_PREFIX}_NUMPY_SIGNATURE "${__${_PYTHON_PREFIX}_NUMPY_SIGNATURE}" CACHE INTERNAL "") - else() - unset (_${_PYTHON_PREFIX}_NUMPY_SIGNATURE CACHE) - endif() - - if (${_PYTHON_PREFIX}_ARTIFACTS_INTERACTIVE) - set (${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR "${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}" CACHE FILEPATH "${_PYTHON_PREFIX} NumPy Include Directory") - endif() - - _python_mark_as_internal (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR - _${_PYTHON_PREFIX}_NUMPY_SIGNATURE) -endif() - -# final validation -if (${_PYTHON_PREFIX}_VERSION_MAJOR AND - NOT ${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) - _python_display_failure ("Could NOT find ${_PYTHON_PREFIX}: Found unsuitable major version \"${${_PYTHON_PREFIX}_VERSION_MAJOR}\", but required major version is exact version \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\"") -endif() - -unset (_${_PYTHON_PREFIX}_REASON_FAILURE) -foreach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Interpreter Compiler Development NumPy) - if (_${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_REASON_FAILURE) - string (APPEND _${_PYTHON_PREFIX}_REASON_FAILURE "\n ${_${_PYTHON_PREFIX}_COMPONENT}: ${_${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_REASON_FAILURE}") - endif() -endforeach() - -include (${CMAKE_CURRENT_LIST_DIR}/../FindPackageHandleStandardArgs.cmake) -find_package_handle_standard_args (${_PYTHON_PREFIX} - REQUIRED_VARS ${_${_PYTHON_PREFIX}_REQUIRED_VARS} - VERSION_VAR ${_PYTHON_PREFIX}_VERSION - HANDLE_COMPONENTS - REASON_FAILURE_MESSAGE "${_${_PYTHON_PREFIX}_REASON_FAILURE}") - -# Create imported targets and helper functions -if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT") - if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS - AND ${_PYTHON_PREFIX}_Interpreter_FOUND - AND NOT TARGET ${_PYTHON_PREFIX}::Interpreter) - add_executable (${_PYTHON_PREFIX}::Interpreter IMPORTED) - set_property (TARGET ${_PYTHON_PREFIX}::Interpreter - PROPERTY IMPORTED_LOCATION "${${_PYTHON_PREFIX}_EXECUTABLE}") - endif() - - if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS - AND ${_PYTHON_PREFIX}_Compiler_FOUND - AND NOT TARGET ${_PYTHON_PREFIX}::Compiler) - add_executable (${_PYTHON_PREFIX}::Compiler IMPORTED) - set_property (TARGET ${_PYTHON_PREFIX}::Compiler - PROPERTY IMPORTED_LOCATION "${${_PYTHON_PREFIX}_COMPILER}") - endif() - - if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS - AND ${_PYTHON_PREFIX}_Development.Module_FOUND) - OR ("Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS - AND ${_PYTHON_PREFIX}_Development.Embed_FOUND)) - - macro (__PYTHON_IMPORT_LIBRARY __name) - if (${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$" - OR ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE) - set (_${_PYTHON_PREFIX}_LIBRARY_TYPE SHARED) - else() - set (_${_PYTHON_PREFIX}_LIBRARY_TYPE STATIC) - endif() - - if (NOT TARGET ${__name}) - add_library (${__name} ${_${_PYTHON_PREFIX}_LIBRARY_TYPE} IMPORTED) - endif() - - set_property (TARGET ${__name} - PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_INCLUDE_DIRS}") - - if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE) - # System manage shared libraries in two parts: import and runtime - if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_LIBRARY_DEBUG) - set_property (TARGET ${__name} PROPERTY IMPORTED_CONFIGURATIONS RELEASE DEBUG) - set_target_properties (${__name} - PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" - IMPORTED_IMPLIB_RELEASE "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}" - IMPORTED_LOCATION_RELEASE "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}") - set_target_properties (${__name} - PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C" - IMPORTED_IMPLIB_DEBUG "${${_PYTHON_PREFIX}_LIBRARY_DEBUG}" - IMPORTED_LOCATION_DEBUG "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG}") - else() - set_target_properties (${__name} - PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C" - IMPORTED_IMPLIB "${${_PYTHON_PREFIX}_LIBRARIES}" - IMPORTED_LOCATION "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}") - endif() - else() - if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_LIBRARY_DEBUG) - set_property (TARGET ${__name} PROPERTY IMPORTED_CONFIGURATIONS RELEASE DEBUG) - set_target_properties (${__name} - PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" - IMPORTED_LOCATION_RELEASE "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}") - set_target_properties (${__name} - PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C" - IMPORTED_LOCATION_DEBUG "${${_PYTHON_PREFIX}_LIBRARY_DEBUG}") - else() - set_target_properties (${__name} - PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C" - IMPORTED_LOCATION "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}") - endif() - endif() - - if (_${_PYTHON_PREFIX}_LIBRARY_TYPE STREQUAL "STATIC") - # extend link information with dependent libraries - _python_get_config_var (_${_PYTHON_PREFIX}_LINK_LIBRARIES LIBS) - if (_${_PYTHON_PREFIX}_LINK_LIBRARIES) - set_property (TARGET ${__name} - PROPERTY INTERFACE_LINK_LIBRARIES ${_${_PYTHON_PREFIX}_LINK_LIBRARIES}) - endif() - endif() - endmacro() - - if (${_PYTHON_PREFIX}_Development.Embed_FOUND) - __python_import_library (${_PYTHON_PREFIX}::Python) - endif() - - if (${_PYTHON_PREFIX}_Development.Module_FOUND) - if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS) - # On Windows/CYGWIN/MSYS, Python::Module is the same as Python::Python - # but ALIAS cannot be used because the imported library is not GLOBAL. - __python_import_library (${_PYTHON_PREFIX}::Module) - else() - if (NOT TARGET ${_PYTHON_PREFIX}::Module) - add_library (${_PYTHON_PREFIX}::Module INTERFACE IMPORTED) - endif() - set_property (TARGET ${_PYTHON_PREFIX}::Module - PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_INCLUDE_DIRS}") - - # When available, enforce shared library generation with undefined symbols - if (APPLE) - set_property (TARGET ${_PYTHON_PREFIX}::Module - PROPERTY INTERFACE_LINK_OPTIONS "LINKER:-undefined,dynamic_lookup") - endif() - if (CMAKE_SYSTEM_NAME STREQUAL "SunOS") - set_property (TARGET ${_PYTHON_PREFIX}::Module - PROPERTY INTERFACE_LINK_OPTIONS "LINKER:-z,nodefs") - endif() - if (CMAKE_SYSTEM_NAME STREQUAL "AIX") - set_property (TARGET ${_PYTHON_PREFIX}::Module - PROPERTY INTERFACE_LINK_OPTIONS "LINKER:-b,erok") - endif() - endif() - endif() - - # - # PYTHON_ADD_LIBRARY ( [STATIC|SHARED|MODULE] src1 src2 ... srcN) - # It is used to build modules for python. - # - function (__${_PYTHON_PREFIX}_ADD_LIBRARY prefix name) - cmake_parse_arguments (PARSE_ARGV 2 PYTHON_ADD_LIBRARY - "STATIC;SHARED;MODULE;WITH_SOABI" "" "") - - if (prefix STREQUAL "Python2" AND PYTHON_ADD_LIBRARY_WITH_SOABI) - message (AUTHOR_WARNING "FindPython2: Option `WITH_SOABI` is not supported for Python2 and will be ignored.") - unset (PYTHON_ADD_LIBRARY_WITH_SOABI) - endif() - - if (PYTHON_ADD_LIBRARY_STATIC) - set (type STATIC) - elseif (PYTHON_ADD_LIBRARY_SHARED) - set (type SHARED) - else() - set (type MODULE) - endif() - - if (type STREQUAL "MODULE" AND NOT TARGET ${prefix}::Module) - message (SEND_ERROR "${prefix}_ADD_LIBRARY: dependent target '${prefix}::Module' is not defined.\n Did you miss to request COMPONENT 'Development.Module'?") - return() - endif() - if (NOT type STREQUAL "MODULE" AND NOT TARGET ${prefix}::Python) - message (SEND_ERROR "${prefix}_ADD_LIBRARY: dependent target '${prefix}::Python' is not defined.\n Did you miss to request COMPONENT 'Development.Embed'?") - return() - endif() - - add_library (${name} ${type} ${PYTHON_ADD_LIBRARY_UNPARSED_ARGUMENTS}) - - get_property (type TARGET ${name} PROPERTY TYPE) - - if (type STREQUAL "MODULE_LIBRARY") - target_link_libraries (${name} PRIVATE ${prefix}::Module) - # customize library name to follow module name rules - set_property (TARGET ${name} PROPERTY PREFIX "") - if(CMAKE_SYSTEM_NAME STREQUAL "Windows") - set_property (TARGET ${name} PROPERTY SUFFIX ".pyd") - endif() - - if (PYTHON_ADD_LIBRARY_WITH_SOABI AND ${prefix}_SOABI) - get_property (suffix TARGET ${name} PROPERTY SUFFIX) - if (NOT suffix) - set (suffix "${CMAKE_SHARED_MODULE_SUFFIX}") - endif() - set_property (TARGET ${name} PROPERTY SUFFIX ".${${prefix}_SOABI}${suffix}") - endif() - else() - if (PYTHON_ADD_LIBRARY_WITH_SOABI) - message (AUTHOR_WARNING "Find${prefix}: Option `WITH_SOABI` is only supported for `MODULE` library type.") - endif() - target_link_libraries (${name} PRIVATE ${prefix}::Python) - endif() - endfunction() - endif() - - if ("NumPy" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_NumPy_FOUND - AND NOT TARGET ${_PYTHON_PREFIX}::NumPy AND TARGET ${_PYTHON_PREFIX}::Module) - add_library (${_PYTHON_PREFIX}::NumPy INTERFACE IMPORTED) - set_property (TARGET ${_PYTHON_PREFIX}::NumPy - PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_NumPy_INCLUDE_DIRS}") - target_link_libraries (${_PYTHON_PREFIX}::NumPy INTERFACE ${_PYTHON_PREFIX}::Module) - endif() -endif() - -# final clean-up - -# Restore CMAKE_FIND_APPBUNDLE -if (DEFINED _${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE) - set (CMAKE_FIND_APPBUNDLE ${_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE}) - unset (_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE) -else() - unset (CMAKE_FIND_APPBUNDLE) -endif() -# Restore CMAKE_FIND_FRAMEWORK -if (DEFINED _${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK) - set (CMAKE_FIND_FRAMEWORK ${_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK}) - unset (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK) -else() - unset (CMAKE_FIND_FRAMEWORK) -endif() diff --git a/scripts/internal/libpython-not-needed-symbols-exported-by-interpreter b/scripts/internal/libpython-not-needed-symbols-exported-by-interpreter deleted file mode 100644 index e69de29b..00000000 diff --git a/scripts/internal/manylinux-aarch64-build-module-wheels.sh b/scripts/internal/manylinux-aarch64-build-module-wheels.sh deleted file mode 100755 index f43a7f87..00000000 --- a/scripts/internal/manylinux-aarch64-build-module-wheels.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -# Run this script inside a dockcross container to build Python wheels for an aarch ITK module. -cd /work -# Update GPG keys -dnf upgrade -y almalinux-release -# Newer Python.cmake module required for SABI -pipx upgrade cmake -yum -y install sudo ninja-build -/opt/python/cp310-cp310/bin/python -m pip install -r /ITKPythonPackage/requirements-dev.txt -for PYBIN in "${PYBINARIES[@]}"; do - ${PYBIN}/pip install -r /ITKPythonPackage/requirements-dev.txt -done - -"/ITKPythonPackage/scripts/internal/manylinux-build-module-wheels.sh" "$@" diff --git a/scripts/internal/manylinux-build-common.sh b/scripts/internal/manylinux-build-common.sh deleted file mode 100644 index 6443b4c0..00000000 --- a/scripts/internal/manylinux-build-common.sh +++ /dev/null @@ -1,85 +0,0 @@ -# Content common to manylinux-build-wheels.sh and -# manylinux-build-module-wheels.sh - -set -e -x - -script_dir=$(cd $(dirname $0) || exit 1; pwd) - -# Versions can be restricted by passing them in as arguments to the script -# For example, -# manylinux-build-wheels.sh cp310 -if [[ $# -eq 0 ]]; then - PYBIN=(/opt/python/*/bin) - PYBINARIES=() - for version in "${PYBIN[@]}"; do - if [[ ${version} == *"cp310"* || ${version} == *"cp311"* ]]; then - PYBINARIES+=(${version}) - fi - done -else - PYBINARIES=() - for version in "$@"; do - PYBINARIES+=(/opt/python/*${version}*/bin) - done -fi - -# i686 or x86_64 ? -case $(uname -m) in - i686) - ARCH=x86 - ;; - x86_64) - ARCH=x64 - ;; - aarch64) - ARCH=aarch64 - ;; - *) - die "Unknown architecture $(uname -m)" - ;; -esac - -# Install prerequirements -export PATH=/work/tools/doxygen-1.8.16/bin:$PATH -case $(uname -m) in - i686) - ARCH=x86 - ;; - x86_64) - if ! type doxygen > /dev/null 2>&1; then - mkdir -p /work/tools - pushd /work/tools > /dev/null 2>&1 - curl https://data.kitware.com/api/v1/file/62c4d615bddec9d0c46cb705/download -o doxygen-1.8.16.linux.bin.tar.gz - tar -xvzf doxygen-1.8.16.linux.bin.tar.gz - popd > /dev/null 2>&1 - fi - ;; - aarch64) - ARCH=aarch64 - if ! type doxygen > /dev/null 2>&1; then - mkdir -p /work/tools - pushd /work/tools > /dev/null 2>&1 - curl https://data.kitware.com/api/v1/file/62c4ed58bddec9d0c46f1388/download -o doxygen-1.8.16.linux.aarch64.bin.tar.gz - tar -xvzf doxygen-1.8.16.linux.aarch64.bin.tar.gz - popd > /dev/null 2>&1 - fi - ;; - *) - die "Unknown architecture $(uname -m)" - ;; -esac -if ! type ninja > /dev/null 2>&1; then - if test ! -d ninja; then - git clone https://github.com/ninja-build/ninja.git - fi - pushd ninja - git checkout release - cmake -Bbuild-cmake -H. - cmake --build build-cmake - cp build-cmake/ninja /usr/local/bin/ - popd -fi - -MANYLINUX_VERSION=${MANYLINUX_VERSION:=_2_28} - -echo "Building wheels for $ARCH using manylinux${MANYLINUX_VERSION}" diff --git a/scripts/internal/manylinux-build-module-wheels.sh b/scripts/internal/manylinux-build-module-wheels.sh deleted file mode 100755 index 37ab0382..00000000 --- a/scripts/internal/manylinux-build-module-wheels.sh +++ /dev/null @@ -1,144 +0,0 @@ -#!/usr/bin/env bash - -# Run this script inside a dockcross container to build Python wheels for an ITK module. -# -# Versions can be restricted by passing them in as arguments to the script. -# For example, -# -# /tmp/dockcross-manylinux-x64 manylinux-build-module-wheels.sh cp310 -# -# Shared library dependencies can be included in the wheel by mounting them to /usr/lib64 or /usr/local/lib64 -# before running this script. -# -# For example, -# -# DOCKER_ARGS="-v /path/to/lib.so:/usr/local/lib64/lib.so" -# /tmp/dockcross-manylinux-x64 -a "$DOCKER_ARGS" manylinux-build-module-wheels.sh -# -# The specialized manylinux container version should be set prior to running this script. -# See https://github.com/dockcross/dockcross for available versions and tags. -# -# For example, `docker run -e ` can be used to set an environment variable when launching a container: -# -# export MANYLINUX_VERSION=2014 -# docker run --rm dockcross/manylinux${MANYLINUX_VERSION}-x64:${IMAGE_TAG} > /tmp/dockcross-manylinux-x64 -# chmod u+x /tmp/dockcross-manylinux-x64 -# /tmp/dockcross-manylinux-x64 -e MANYLINUX_VERSION manylinux-build-module-wheels.sh cp310 -# - -# ----------------------------------------------------------------------- -# Script argument parsing -# -usage() -{ - echo "Usage: - manylinux-build-module-wheels - [ -h | --help ] show usage - [ -c | --cmake_options ] space-separated string of CMake options to forward to the module (e.g. \"--config-setting=cmake.define.BUILD_TESTING=OFF\") - [ -x | --exclude_libs ] semicolon-separated library names to exclude when repairing wheel (e.g. \"libcuda.so\") - [ python_version ] build wheel for a specific python version. (e.g. cp310)" - exit 2 -} - -PARSED_ARGS=$(getopt -a -n dockcross-manylinux-download-cache-and-build-module-wheels \ - -o hc:x: --long help,cmake_options:,exclude_libs: -- "$@") -eval set -- "$PARSED_ARGS" - -while : -do - case "$1" in - -h | --help) usage; break ;; - -c | --cmake_options) CMAKE_OPTIONS="$2" ; shift 2 ;; - -x | --exclude_libs) EXCLUDE_LIBS="$2" ; shift 2 ;; - --) shift; break ;; - *) echo "Unexpected option: $1."; - usage; break ;; - esac -done - -PYTHON_VERSION="$@" -# ----------------------------------------------------------------------- - -# ----------------------------------------------------------------------- -# These variables are set in common script: -# -ARCH="" -PYBINARIES="" - -script_dir=$(cd $(dirname $0) || exit 1; pwd) -source "${script_dir}/manylinux-build-common.sh" -# ----------------------------------------------------------------------- - -# Set up library paths in container so that shared libraries can be added to wheels -sudo ldconfig -export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/work/oneTBB-prefix/lib:/usr/lib:/usr/lib64:/usr/local/lib:/usr/local/lib64 - -# Compile wheels re-using standalone project and archive cache -for PYBIN in "${PYBINARIES[@]}"; do - Python3_EXECUTABLE=${PYBIN}/python - Python3_INCLUDE_DIR=$( find -L ${PYBIN}/../include/ -name Python.h -exec dirname {} \; ) - - echo "" - echo "Python3_EXECUTABLE:${Python3_EXECUTABLE}" - echo "Python3_INCLUDE_DIR:${Python3_INCLUDE_DIR}" - - if [[ -e /work/requirements-dev.txt ]]; then - sudo ${PYBIN}/pip install --upgrade -r /work/requirements-dev.txt - fi - if [[ -e /ITKPythonPackage/requirements-dev.txt ]]; then - sudo ${PYBIN}/pip install --upgrade -r /ITKPythonPackage/requirements-dev.txt - fi - version=$(basename $(dirname ${PYBIN})) - # Remove "m" -- not present in Python 3.8 and later - version=${version:0:9} - itk_build_dir=/work/$(basename /ITKPythonPackage/ITK-${version}*-manylinux${MANYLINUX_VERSION}_${ARCH}) - ln -fs /ITKPythonPackage/ITK-${version}*-manylinux${MANYLINUX_VERSION}_${ARCH} $itk_build_dir - if [[ ! -d ${itk_build_dir} ]]; then - echo 'ITK build tree not available!' 1>&2 - exit 1 - fi - itk_source_dir=/work/ITK-source/ITK - ln -fs /ITKPythonPackage/ITK-source/ /work/ITK-source - if [[ ! -d ${itk_source_dir} ]]; then - echo 'ITK source tree not available!' 1>&2 - exit 1 - fi - py_minor=$(echo $version | cut -d '-' -f 1 | cut -d '3' -f 2) - wheel_py_api="" - if test $py_minor -ge 11; then - wheel_py_api=cp3$py_minor - fi - ${PYBIN}/python -m build \ - --verbose \ - --wheel \ - --outdir dist \ - --no-isolation \ - --skip-dependency-check \ - --config-setting=cmake.define.ITK_DIR:PATH=${itk_build_dir} \ - --config-setting=cmake.define.WRAP_ITK_INSTALL_COMPONENT_IDENTIFIER:STRING=PythonWheel \ - --config-setting=cmake.define.CMAKE_CXX_COMPILER_TARGET:STRING=$(uname -m)-linux-gnu \ - --config-setting=cmake.define.CMAKE_INSTALL_LIBDIR:STRING=lib \ - --config-setting=cmake.define.PY_SITE_PACKAGES_PATH:PATH="." \ - --config-setting=wheel.py-api=$wheel_py_api \ - --config-setting=cmake.define.BUILD_TESTING:BOOL=OFF \ - --config-setting=cmake.define.Python3_EXECUTABLE:FILEPATH=${Python3_EXECUTABLE} \ - --config-setting=cmake.define.Python3_INCLUDE_DIR:PATH=${Python3_INCLUDE_DIR} \ - ${CMAKE_OPTIONS//'-D'/'--config-setting=cmake.define.'} \ - || exit 1 -done - -# Convert list of excluded libs in --exclude_libs to auditwheel --exclude options -if test -n "$EXCLUDE_LIBS"; then - AUDITWHEEL_EXCLUDE_ARGS="--exclude ${EXCLUDE_LIBS//;/ --exclude }" -fi - -sudo ${Python3_EXECUTABLE} -m pip install auditwheel -for whl in dist/*linux*$(uname -m).whl; do - auditwheel repair ${whl} -w /work/dist/ ${AUDITWHEEL_EXCLUDE_ARGS} -done - -if compgen -G "dist/itk*-linux*.whl" > /dev/null; then - for itk_wheel in dist/itk*-linux*.whl; do - rm ${itk_wheel} - done -fi diff --git a/scripts/internal/manylinux-build-wheels.sh b/scripts/internal/manylinux-build-wheels.sh deleted file mode 100755 index 2ebacbec..00000000 --- a/scripts/internal/manylinux-build-wheels.sh +++ /dev/null @@ -1,215 +0,0 @@ -#!/usr/bin/env bash - -# Run this script inside a dockcross container to build Python wheels for ITK. -# -# Versions can be restricted by passing them in as arguments to the script. -# For example, -# -# /tmp/dockcross-manylinux-x64 manylinux-build-wheels.sh cp310 -# -# Shared library dependencies can be included wheels by mounting them to /usr/lib64 or /usr/local/lib64 -# before running this script. -# -# For example, -# -# DOCKER_ARGS="-v /path/to/lib.so:/usr/local/lib64/lib.so" -# /tmp/dockcross-manylinux-x64 -a "$DOCKER_ARGS" manylinux-build-wheels.sh -# -# The specialized manylinux container version should be set prior to running this script. -# See https://github.com/dockcross/dockcross for available versions and tags. -# -# For example, `docker run -e ` can be used to set an environment variable when launching a container: -# -# export MANYLINUX_VERSION=2014 -# docker run --rm dockcross/manylinux${MANYLINUX_VERSION}-x64:${IMAGE_TAG} > /tmp/dockcross-manylinux-x64 -# chmod u+x /tmp/dockcross-manylinux-x64 -# /tmp/dockcross-manylinux-x64 -e MANYLINUX_VERSION manylinux-build-module-wheels.sh cp310 -# - -# ----------------------------------------------------------------------- -# These variables are set in common script: -# -ARCH="" -PYBINARIES="" -Python3_LIBRARY="" - -script_dir=$(cd $(dirname $0) || exit 1; pwd) -source "${script_dir}/manylinux-build-common.sh" - -# ----------------------------------------------------------------------- - -# Build standalone project and populate archive cache -mkdir -p /work/ITK-source -pushd /work/ITK-source > /dev/null 2>&1 - cmake -DITKPythonPackage_BUILD_PYTHON:PATH=0 -G Ninja ../ - ninja -popd > /dev/null 2>&1 -tbb_dir=/work/oneTBB-prefix/lib/cmake/TBB -# So auditwheel can find the libs -sudo ldconfig -export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/work/oneTBB-prefix/lib:/usr/lib:/usr/lib64 - -# TODO: More work is required to re-enable this feature. -SINGLE_WHEEL=0 - -# Compile wheels re-using standalone project and archive cache -for PYBIN in "${PYBINARIES[@]}"; do - export Python3_EXECUTABLE=${PYBIN}/python3 - Python3_INCLUDE_DIR=$( find -L ${PYBIN}/../include/ -name Python.h -exec dirname {} \; ) - - echo "" - echo "Python3_EXECUTABLE:${Python3_EXECUTABLE}" - echo "Python3_INCLUDE_DIR:${Python3_INCLUDE_DIR}" - - # Install dependencies - sudo ${PYBIN}/pip install --upgrade -r /work/requirements-dev.txt - - build_type="Release" - compile_flags="-O3 -DNDEBUG" - source_path=/work/ITK-source/ITK - build_path=/work/ITK-$(basename $(dirname ${PYBIN}))-manylinux${MANYLINUX_VERSION}_${ARCH} - PYPROJECT_CONFIGURE="${script_dir}/../pyproject_configure.py" - - # Clean up previous invocations - # rm -rf ${build_path} - - if [[ ${SINGLE_WHEEL} == 1 ]]; then - - echo "#" - echo "# Build single ITK wheel" - echo "#" - - # Configure pyproject.toml - ${PYBIN}/python ${PYPROJECT_CONFIGURE} "itk" - # Generate wheel - ${PYBIN}/python -m build \ - --verbose \ - --wheel \ - --outdir dist \ - --no-isolation \ - --skip-dependency-check \ - --config-setting=cmake.define.ITK_SOURCE_DIR:PATH=${source_path} \ - --config-setting=cmake.define.ITK_BINARY_DIR:PATH=${build_path} \ - --config-setting=cmake.define.ITKPythonPackage_ITK_BINARY_REUSE:BOOL=OFF \ - --config-setting=cmake.define.ITKPythonPackage_WHEEL_NAME:STRING=itk \ - --config-setting=cmake.define.CMAKE_CXX_COMPILER_TARGET:STRING=$(uname -m)-linux-gnu \ - "--config-setting=cmake.define.CMAKE_CXX_FLAGS:STRING=$compile_flags" \ - "--config-setting=cmake.define.CMAKE_C_FLAGS:STRING=$compile_flags" \ - "--config-setting=cmake.define.CMAKE_BUILD_TYPE:STRING=${build_type}" \ - --config-setting=cmake.define.Python3_EXECUTABLE:FILEPATH=${Python3_EXECUTABLE} \ - --config-setting=cmake.define.Python3_INCLUDE_DIR:PATH=${Python3_INCLUDE_DIR} \ - --config-setting=cmake.define.Module_ITKTBB:BOOL=ON \ - --config-setting=cmake.define.TBB_DIR:PATH=${tbb_dir} \ - . - - else - - echo "#" - echo "# Build multiple ITK wheels" - echo "#" - - # Build ITK python - ( - mkdir -p ${build_path} \ - && cd ${build_path} \ - && cmake \ - -DCMAKE_BUILD_TYPE:STRING=${build_type} \ - -DITK_SOURCE_DIR:PATH=${source_path} \ - -DITK_BINARY_DIR:PATH=${build_path} \ - -DBUILD_TESTING:BOOL=OFF \ - -DPython3_EXECUTABLE:FILEPATH=${Python3_EXECUTABLE} \ - -DPython3_INCLUDE_DIR:PATH=${Python3_INCLUDE_DIR} \ - -DCMAKE_CXX_COMPILER_TARGET:STRING=$(uname -m)-linux-gnu \ - -DCMAKE_CXX_FLAGS:STRING="$compile_flags" \ - -DCMAKE_C_FLAGS:STRING="$compile_flags" \ - -DCMAKE_BUILD_TYPE:STRING="${build_type}" \ - -DWRAP_ITK_INSTALL_COMPONENT_IDENTIFIER:STRING=PythonWheel \ - -DWRAP_ITK_INSTALL_COMPONENT_PER_MODULE:BOOL=ON \ - -DITK_WRAP_unsigned_short:BOOL=ON \ - -DITK_WRAP_double:BOOL=ON \ - -DITK_WRAP_complex_double:BOOL=ON \ - -DITK_WRAP_IMAGE_DIMS:STRING="2;3;4" \ - -DPY_SITE_PACKAGES_PATH:PATH="." \ - -DITK_LEGACY_SILENT:BOOL=ON \ - -DITK_WRAP_PYTHON:BOOL=ON \ - -DITK_WRAP_DOC:BOOL=ON \ - -DModule_ITKTBB:BOOL=ON \ - -DTBB_DIR:PATH=${tbb_dir} \ - -G Ninja \ - ${source_path} \ - && ninja \ - || exit 1 - ) - - wheel_names=$(cat ${script_dir}/../WHEEL_NAMES.txt) - for wheel_name in ${wheel_names}; do - # Configure pyproject.toml - ${PYBIN}/python ${PYPROJECT_CONFIGURE} ${wheel_name} - # Generate wheel - ${PYBIN}/python -m build \ - --verbose \ - --wheel \ - --outdir dist \ - --no-isolation \ - --skip-dependency-check \ - --config-setting=cmake.define.ITK_SOURCE_DIR:PATH=${source_path} \ - --config-setting=cmake.define.ITK_BINARY_DIR:PATH=${build_path} \ - --config-setting=cmake.define.ITKPythonPackage_ITK_BINARY_REUSE:BOOL=ON \ - --config-setting=cmake.define.ITKPythonPackage_WHEEL_NAME:STRING=${wheel_name} \ - --config-setting=cmake.define.Python3_EXECUTABLE:FILEPATH=${Python3_EXECUTABLE} \ - --config-setting=cmake.define.Python3_INCLUDE_DIR:PATH=${Python3_INCLUDE_DIR} \ - --config-setting=cmake.define.CMAKE_CXX_FLAGS:STRING="${compile_flags}" \ - --config-setting=cmake.define.CMAKE_C_FLAGS:STRING="${compile_flags}" \ - . \ - || exit 1 - done - fi - - # Remove unnecessary files for building against ITK - find ${build_path} -name '*.cpp' -delete -o -name '*.xml' -delete - rm -rf ${build_path}/Wrapping/Generators/castxml* - find ${build_path} -name '*.o' -delete - -done - -sudo /opt/python/cp311-cp311/bin/pip3 install auditwheel wheel - -if test "${ARCH}" == "x64"; then - # This step will fixup the wheel switching from 'linux' to 'manylinux' tag - for whl in dist/itk_*linux_*.whl; do - /opt/python/cp311-cp311/bin/auditwheel repair --plat manylinux${MANYLINUX_VERSION}_x86_64 ${whl} -w /work/dist/ - done -else - for whl in dist/itk_*$(uname -m).whl; do - /opt/python/cp311-cp311/bin/auditwheel repair ${whl} -w /work/dist/ - done -fi - -# auditwheel does not process this "metawheel" correctly since it does not -# have any native SO's. -mkdir -p metawheel-dist -for whl in dist/itk-*linux_*.whl; do - /opt/python/cp311-cp311/bin/wheel unpack --dest metawheel ${whl} - manylinux_version=manylinux${MANYLINUX_VERSION} - new_tag=$(basename ${whl/linux/${manylinux_version}} .whl) - sed -i "s/Tag: .*/Tag: ${new_tag}/" metawheel/itk-*/itk*.dist-info/WHEEL - /opt/python/cp311-cp311/bin/wheel pack --dest metawheel-dist metawheel/itk-* - mv metawheel-dist/*.whl dist/${new_tag}.whl - rm -rf metawheel -done -rm -rf metawheel-dist -rm dist/itk-*-linux_*.whl -rm dist/itk_*-linux_*.whl - -# Install packages and test -for PYBIN in "${PYBINARIES[@]}"; do - ${PYBIN}/pip install --user numpy - sudo ${PYBIN}/pip install --upgrade pip - ${PYBIN}/pip install itk --user --no-cache-dir --no-index -f /work/dist - (cd $HOME && ${PYBIN}/python -c 'from itk import ITKCommon;') - (cd $HOME && ${PYBIN}/python -c 'import itk; image = itk.Image[itk.UC, 2].New()') - (cd $HOME && ${PYBIN}/python -c 'import itkConfig; itkConfig.LazyLoading = False; import itk;') - (cd $HOME && ${PYBIN}/python ${script_dir}/../../docs/code/test.py ) -done - -rm -f dist/numpy*.whl diff --git a/scripts/internal/shellcheck-run.sh b/scripts/internal/shellcheck-run.sh deleted file mode 100755 index e110bb79..00000000 --- a/scripts/internal/shellcheck-run.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash - -set -e -set -o pipefail - -( -exit_code=0 - -# -# SC1090: Can't follow non-constant source. Use a directive to specify location. -# SC2006: Use $(..) instead of legacy `..`. -# SC2046: Quote this to prevent word splitting. -# SC2086: Double quote to prevent globbing and word splitting. -# SC2153: Possible misspelling: SCRIPT_DIR may not be assigned, but script_dir is. -# SC2155: Declare and assign separately to avoid masking return values. -# - -# find all executables and run `shellcheck` -for f in $(find . -type f -not -iwholename '*.git*' | sort -u); do - if file "$f" | grep --quiet -e shell -e bash; then - shellcheck \ - -e SC1090 \ - -e SC2046 \ - -e SC2086 \ - "$f" \ - && echo "[OK]: successfully linted $f" || echo "[FAILED]: found issues linting $f" - current_exit_code=$? - if [[ $current_exit_code != 0 ]]; then - exit_code=$current_exit_code - fi - fi -done - -exit $exit_code -) diff --git a/scripts/internal/wheel_builder_utils.py b/scripts/internal/wheel_builder_utils.py deleted file mode 100644 index 422d4f51..00000000 --- a/scripts/internal/wheel_builder_utils.py +++ /dev/null @@ -1,95 +0,0 @@ -"""This module provides convenient function facilitating scripting. - -These functions have been copied from scikit-build project. -See https://github.com/scikit-build/scikit-build -""" - -import errno -import os - -from contextlib import contextmanager -from functools import wraps - - -def mkdir_p(path): - """Ensure directory ``path`` exists. If needed, parent directories - are created. - - Adapted from http://stackoverflow.com/a/600612/1539918 - """ - try: - os.makedirs(path) - except OSError as exc: # Python >2.5 - if exc.errno == errno.EEXIST and os.path.isdir(path): - pass - else: # pragma: no cover - raise - - -@contextmanager -def push_env(**kwargs): - """This context manager allow to set/unset environment variables.""" - saved_env = dict(os.environ) - for var, value in kwargs.items(): - if value is not None: - os.environ[var] = value - elif var in os.environ: - del os.environ[var] - yield - os.environ.clear() - for saved_var, saved_value in saved_env.items(): - os.environ[saved_var] = saved_value - - -class ContextDecorator(object): - """A base class or mixin that enables context managers to work as - decorators.""" - - def __init__(self, **kwargs): - self.__dict__.update(kwargs) - - def __enter__(self): - # Note: Returning self means that in "with ... as x", x will be self - return self - - def __exit__(self, typ, val, traceback): - pass - - def __call__(self, func): - @wraps(func) - def inner(*args, **kwds): # pylint:disable=missing-docstring - with self: - return func(*args, **kwds) - - return inner - - -class push_dir(ContextDecorator): - """Context manager to change current directory.""" - - def __init__(self, directory=None, make_directory=False): - """ - :param directory: - Path to set as current working directory. If ``None`` - is passed, ``os.getcwd()`` is used instead. - - :param make_directory: - If True, ``directory`` is created. - """ - self.directory = None - self.make_directory = None - self.old_cwd = None - super(push_dir, self).__init__( - directory=directory, make_directory=make_directory - ) - - def __enter__(self): - self.old_cwd = os.getcwd() - if self.directory: - if self.make_directory: - mkdir_p(self.directory) - os.chdir(self.directory) - return self - - def __exit__(self, typ, val, traceback): - os.chdir(self.old_cwd) diff --git a/scripts/internal/windows_build_common.py b/scripts/internal/windows_build_common.py deleted file mode 100644 index 4cf2c739..00000000 --- a/scripts/internal/windows_build_common.py +++ /dev/null @@ -1,60 +0,0 @@ -__all__ = ["DEFAULT_PY_ENVS", "venv_paths"] - -from subprocess import check_call -import os -import shutil - -DEFAULT_PY_ENVS = ["310-x64", "311-x64"] - -SCRIPT_DIR = os.path.dirname(__file__) -ROOT_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, "..", "..")) - - -def venv_paths(python_version): - # Create venv - venv_executable = "C:/Python%s/Scripts/virtualenv.exe" % (python_version) - venv_dir = os.path.join(ROOT_DIR, "venv-%s" % python_version) - check_call([venv_executable, venv_dir]) - - python_executable = os.path.join(venv_dir, "Scripts", "python.exe") - python_include_dir = "C:/Python%s/include" % (python_version) - - # XXX It should be possible to query skbuild for the library dir associated - # with a given interpreter. - xy_ver = python_version.split("-")[0] - - # Version-specific library (e.g., python311.lib) - required for - # CMake's FindPython3 to extract version info for Development.Module - python_library = "C:/Python%s/libs/python%s.lib" % (python_version, xy_ver) - - # Stable ABI library (python3.lib) - for Development.SABIModule - if int(xy_ver[1:]) >= 11: - python_sabi_library = "C:/Python%s/libs/python3.lib" % (python_version) - else: - python_sabi_library = python_library - - print("") - print("Python3_EXECUTABLE: %s" % python_executable) - print("Python3_INCLUDE_DIR: %s" % python_include_dir) - print("Python3_LIBRARY: %s" % python_library) - print("Python3_SABI_LIBRARY: %s" % python_sabi_library) - - pip = os.path.join(venv_dir, "Scripts", "pip.exe") - - ninja_executable = os.path.join(venv_dir, "Scripts", "ninja.exe") - if not os.path.exists(ninja_executable): - ninja_executable = shutil.which("ninja.exe") - print("NINJA_EXECUTABLE:%s" % ninja_executable) - - # Update PATH - path = os.path.join(venv_dir, "Scripts") - - return ( - python_executable, - python_include_dir, - python_library, - python_sabi_library, - pip, - ninja_executable, - path, - ) diff --git a/scripts/lint-shell-scripts.sh b/scripts/lint-shell-scripts.sh deleted file mode 100755 index 47e10c9a..00000000 --- a/scripts/lint-shell-scripts.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -set -e -set -o pipefail - -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -pushd $SCRIPT_DIR > /dev/null - -docker run --rm -it \ - --name df-shellcheck \ - -v $(pwd):/usr/src:ro \ - --workdir /usr/src \ - r.j3ss.co/shellcheck ./internal/shellcheck-run.sh - -exit_code=$? - -popd > /dev/null - -exit $exit_code diff --git a/scripts/linux_build_python_instance.py b/scripts/linux_build_python_instance.py new file mode 100644 index 00000000..4f2ea72e --- /dev/null +++ b/scripts/linux_build_python_instance.py @@ -0,0 +1,278 @@ +import os +import shutil +from pathlib import Path + +from build_python_instance_base import BuildPythonInstanceBase +from wheel_builder_utils import ( + _remove_tree, +) + + +class LinuxBuildPythonInstance(BuildPythonInstanceBase): + """Linux-specific wheel builder. + + Handles manylinux container builds, ``auditwheel`` wheel repair, and + Linux-specific compiler/target triple configuration. + """ + + def prepare_build_env(self) -> None: + """Set up the Linux build environment, TBB paths, and compiler targets.""" + # ############################################# + # ### Setup build tools + self.package_env_config["USE_TBB"] = "ON" + self.package_env_config["TBB_DIR"] = ( + self.build_dir_root / "build" / "oneTBB-prefix" / "lib" / "cmake" / "TBB" + ) + + # The interpreter is provided; ensure basic tools are available + self.venv_paths() + self.update_venv_itk_build_configurations() + if self.package_env_config["ARCH"] == "x64": + target_triple = "x86_64-linux-gnu" + elif self.package_env_config["ARCH"] in ("aarch64", "arm64"): + target_triple = "aarch64-linux-gnu" + elif self.package_env_config["ARCH"] == "x86": + target_triple = "i686-linux-gnu" + else: + target_triple = f"{self.package_env_config['ARCH']}-linux-gnu" + + target_arch = self.package_env_config["ARCH"] + + self.cmake_compiler_configurations.set( + "CMAKE_CXX_COMPILER_TARGET:STRING", target_triple + ) + + # build will be here is downloaded + itk_binary_build_name: Path = ( + self.build_dir_root + / "build" + / f"ITK-{self.platform_env}-{self.get_pixi_environment_name()}_{target_arch}" + ) + + self.cmake_itk_source_build_configurations.set( + "ITK_BINARY_DIR:PATH", itk_binary_build_name.as_posix() + ) + + # Keep values consistent with prior quoting behavior + # self.cmake_compiler_configurations.set("CMAKE_CXX_FLAGS:STRING", "-O3 -DNDEBUG") + # self.cmake_compiler_configurations.set("CMAKE_C_FLAGS:STRING", "-O3 -DNDEBUG") + + def post_build_fixup(self) -> None: + """Repair wheels with ``auditwheel`` and retag the ITK meta-wheel.""" + manylinux_ver: str | None = self.package_env_config.get( + "MANYLINUX_VERSION", None + ) + if manylinux_ver: + # Repair all produced wheels with auditwheel for packages with so elements (starts with itk_) + whl = None + # cp39-cp39-linux itk_segmentation-6.0.0b2-cp39-cp39-linux_x86_64.whl + # Extract Python version from platform_env + if "-" in self.platform_env: + # in manylinux case, platform env is manylinux-cp310, for example, don't want anything before '-' + py_version = self.platform_env.split("-")[-1] + else: + py_version = self.platform_env + cp_prefix: str = py_version.replace("py", "cp").replace(".", "") + binary_wheel_glob_pattern: str = f"itk_*-*{cp_prefix}*-linux_*.whl" + dist_path: Path = self.build_dir_root / "dist" + for whl in dist_path.glob(binary_wheel_glob_pattern): + if whl.name.startswith("itk-"): + print( + f"Skipping the itk-meta wheel that has nothing to fixup {whl}" + ) + continue + self.fixup_wheel(str(whl)) + del whl + # Retag meta-wheel: Special handling for the itk meta wheel to adjust tag + # auditwheel does not process this "metawheel" correctly since it does not + # have any native SO's. + meta_wheel_glob_pattern: str = f"itk-*-*{cp_prefix}*-linux_*.whl" + for metawhl in dist_path.glob(meta_wheel_glob_pattern): + # Unpack, edit WHEEL tag, repack + metawheel_dir = self.build_dir_root / "metawheel" + metawheel_dir.mkdir(parents=True, exist_ok=True) + self.echo_check_call( + [ + self.package_env_config["PYTHON_EXECUTABLE"], + "-m", + "wheel", + "unpack", + "--dest", + str(metawheel_dir), + str(metawhl), + ] + ) + # Find unpacked dir + unpacked_dirs = list(metawheel_dir.glob("itk-*/itk*.dist-info/WHEEL")) + for wheel_file in unpacked_dirs: + content = wheel_file.read_text(encoding="utf-8").splitlines() + base = metawhl.name + if len(manylinux_ver) > 0: + base = metawhl.name.replace( + "linux", f"manylinux{manylinux_ver}" + ) + # Wheel filename: {name}-{version}-{python}-{abi}-{platform}.whl + # Tag must be only "{python}-{abi}-{platform}", not the full stem. + stem = Path(base).stem + parts = stem.split("-") + tag = "-".join(parts[-3:]) + new = [] + for line in content: + if line.startswith("Tag: "): + new.append(f"Tag: {tag}") + else: + new.append(line) + wheel_file.write_text("\n".join(new) + "\n", encoding="utf-8") + for fixed_dir in metawheel_dir.glob("itk-*"): + metawheel_dist = self.build_dir_root / "metawheel-dist" + metawheel_dist.mkdir(parents=True, exist_ok=True) + self.echo_check_call( + [ + self.package_env_config["PYTHON_EXECUTABLE"], + "-m", + "wheel", + "pack", + "--dest", + str(metawheel_dist), + str(fixed_dir), + ] + ) + # Move and clean + for new_whl in metawheel_dist.glob("*.whl"): + shutil.move( + str(new_whl), + str((self.build_dir_root / "dist") / new_whl.name), + ) + # Remove old and temp + try: + metawhl.unlink() + except OSError: + pass + _remove_tree(metawheel_dir) + _remove_tree(metawheel_dist) + + def fixup_wheel( + self, filepath, lib_paths: str = "", remote_module_wheel: bool = False + ) -> None: + """Repair a wheel with ``auditwheel`` and apply manylinux platform tags. + + Parameters + ---------- + filepath : str + Path to the ``.whl`` file. + lib_paths : str, optional + Unused on Linux (kept for interface compatibility). + remote_module_wheel : bool, optional + If True, output repaired wheel to the remote module's ``dist/`` + directory instead of the main build ``dist/``. + """ + # Use auditwheel to repair wheels and set manylinux tags + manylinux_ver = self.package_env_config.get("MANYLINUX_VERSION", "") + if len(manylinux_ver) > 1: + plat = None + if self.package_env_config["ARCH"] == "x64" and manylinux_ver: + plat = f"manylinux{manylinux_ver}_x86_64" + cmd = [ + self.package_env_config["PYTHON_EXECUTABLE"], + "-m", + "auditwheel", + "repair", + ] + if plat: + cmd += ["--plat", plat] + cmd += [ + str(filepath), + "-w", + ( + str(self.module_source_dir / "dist") + if remote_module_wheel + else str(self.build_dir_root / "dist") + ), + ] + # Provide LD_LIBRARY_PATH for oneTBB and common system paths + extra_lib = str( + self.package_env_config["IPP_SUPERBUILD_BINARY_DIR"].parent + / "oneTBB-prefix" + / "lib" + ) + env = dict(self.package_env_config) + env["LD_LIBRARY_PATH"] = ":".join( + [ + env.get("LD_LIBRARY_PATH", ""), + extra_lib, + "/usr/lib64", + "/usr/lib", + ] + ) + print(f'RUNNING WITH PATH {os.environ["PATH"]}') + env["PATH"] = os.environ["PATH"] + self.echo_check_call(cmd, env=env) + + # Remove the original linux_*.whl after successful repair + filepath_obj = Path(filepath) + if ( + filepath_obj.exists() + and "-linux_" in filepath_obj.name + and filepath_obj.suffix == ".whl" + ): + print( + f"Removing original linux wheel after repair: {filepath_obj.name}" + ) + try: + _remove_tree(filepath_obj) + except OSError as e: + print(f"Warning: Could not remove {filepath_obj.name}: {e}") + else: + print( + "Building outside of manylinux environment does not require wheel fixups." + ) + return + + def build_tarball(self): + """Create a zstd-compressed tarball of the ITK build tree.""" + self.create_posix_tarball() + + def discover_python_venvs( + self, platform_os_name: str, platform_architechure: str + ) -> list[str]: + """Discover available CPython installs on Linux. + + Checks ``/opt/python`` (manylinux) and the project ``venvs/`` + directory. + + Parameters + ---------- + platform_os_name : str + Operating system identifier (unused, kept for interface). + platform_architechure : str + Architecture identifier (unused, kept for interface). + + Returns + ------- + list[str] + Sorted list of discovered environment names. + """ + names = [] + + # Discover virtualenvs under project 'venvs' folder + def _discover_ipp_venvs() -> list[str]: + venvs_dir = self.build_dir_root / "venvs" + if not venvs_dir.exists(): + return [] + names.extend([p.name for p in venvs_dir.iterdir() if p.is_dir()]) + # Sort for stable order + return sorted(names) + + # Discover available manylinux CPython installs under /opt/python + def _discover_manylinuxlocal_pythons() -> list[str]: + base = Path("/opt/python") + if not base.exists(): + return [] + names.extend([p.name for p in base.iterdir() if p.is_dir()]) + return sorted(names) + + default_platform_envs = ( + _discover_manylinuxlocal_pythons() + _discover_ipp_venvs() + ) + + return default_platform_envs diff --git a/scripts/macos_build_python_instance.py b/scripts/macos_build_python_instance.py new file mode 100644 index 00000000..4b04fcc8 --- /dev/null +++ b/scripts/macos_build_python_instance.py @@ -0,0 +1,140 @@ +from pathlib import Path + +from build_python_instance_base import BuildPythonInstanceBase + + +class MacOSBuildPythonInstance(BuildPythonInstanceBase): + """macOS-specific wheel builder. + + Handles macOS deployment target and architecture settings, and uses + ``delocate`` for wheel repair on x86_64 builds. + """ + + def prepare_build_env(self) -> None: + """Set up the macOS build environment, deployment target, and architecture.""" + # ############################################# + # ### Setup build tools + self.package_env_config["USE_TBB"] = "OFF" + self.package_env_config["TBB_DIR"] = "NOT_FOUND" + + # The interpreter is provided; ensure basic tools are available + self.venv_paths() + self.update_venv_itk_build_configurations() + macosx_target = self.package_env_config.get("MACOSX_DEPLOYMENT_TARGET", "") + if macosx_target: + self.cmake_compiler_configurations.set( + "CMAKE_OSX_DEPLOYMENT_TARGET:STRING", macosx_target + ) + + target_arch = self.package_env_config["ARCH"] + + self.cmake_compiler_configurations.set( + "CMAKE_OSX_ARCHITECTURES:STRING", target_arch + ) + + # build will be here if downloaded + binaries_path = Path( + self.build_dir_root + / "build" + / f"ITK-{self.platform_env}-{self.platform_env}_{target_arch}" + ) + + if Path(binaries_path).exists(): + itk_binary_build_name = binaries_path + else: + itk_binary_build_name: Path = ( + self.build_dir_root + / "build" + / f"ITK-{self.platform_env}-{self.get_pixi_environment_name()}_{target_arch}" + ) + + self.cmake_itk_source_build_configurations.set( + "ITK_BINARY_DIR:PATH", itk_binary_build_name.as_posix() + ) + + # Keep values consistent with prior quoting behavior + # self.cmake_compiler_configurations.set("CMAKE_CXX_FLAGS:STRING", "-O3 -DNDEBUG") + # self.cmake_compiler_configurations.set("CMAKE_C_FLAGS:STRING", "-O3 -DNDEBUG") + + def post_build_fixup(self) -> None: + """Run ``delocate`` on x86_64 wheels to bundle shared libraries.""" + # delocate on macOS x86_64 only + if self.package_env_config["ARCH"] == "x86_64": + self.fixup_wheels() + + def build_tarball(self): + """Create a zstd-compressed tarball of the ITK build tree.""" + self.create_posix_tarball() + + def discover_python_venvs( + self, platform_os_name: str, platform_architechure: str + ) -> list[str]: + """Discover available Python environments under the project ``venvs/`` dir. + + Parameters + ---------- + platform_os_name : str + Operating system identifier (unused, kept for interface). + platform_architechure : str + Architecture identifier (unused, kept for interface). + + Returns + ------- + list[str] + Sorted list of discovered environment names. + """ + names = [] + + # Discover virtualenvs under project 'venvs' folder + def _discover_ipp_venvs() -> list[str]: + venvs_dir = self.build_dir_root / "venvs" + if not venvs_dir.exists(): + return [] + names.extend([p.name for p in venvs_dir.iterdir() if p.is_dir()]) + # Sort for stable order + return sorted(names) + + default_platform_envs = _discover_ipp_venvs() + + return default_platform_envs + + def fixup_wheel( + self, filepath, lib_paths: str = "", remote_module_wheel: bool = False + ) -> None: + """Repair a wheel using ``delocate`` on x86_64, cleaning AppleDouble files first. + + Parameters + ---------- + filepath : str + Path to the ``.whl`` file. + lib_paths : str, optional + Unused on macOS (kept for interface compatibility). + remote_module_wheel : bool, optional + Unused on macOS (kept for interface compatibility). + """ + self.remove_apple_double_files() + # macOS fix-up with delocate (only needed for x86_64) + if self.package_env_config["ARCH"] != "arm64": + venv_bin_path = self.venv_info_dict.get("venv_bin_path", None) + if venv_bin_path: + delocate_listdeps = f"{venv_bin_path}/delocate-listdeps" + delocate_wheel = f"{venv_bin_path}/delocate-wheel" + self.echo_check_call([str(delocate_listdeps), str(filepath)]) + self.echo_check_call([str(delocate_wheel), str(filepath)]) + else: + print( + "=" * 20 + + "WARNING: Could not find venv binary to delocate wheel" + + "=" * 20 + ) + + def remove_apple_double_files(self): + """Remove AppleDouble ``._*`` files using ``dot_clean`` if available.""" + try: + # Optional: clean AppleDouble files if tool is available + self.echo_check_call( + ["dot_clean", str(self.package_env_config["IPP_SOURCE_DIR"])] + ) + except Exception: + # dot_clean may not be available; continue without it + pass diff --git a/scripts/macpython-build-common.sh b/scripts/macpython-build-common.sh deleted file mode 100644 index 123ced58..00000000 --- a/scripts/macpython-build-common.sh +++ /dev/null @@ -1,79 +0,0 @@ -# Content common to macpython-build-wheels.sh and -# macpython-build-module-wheels.sh - -set -e -x - -SCRIPT_DIR=$(cd $(dirname $0) || exit 1; pwd) - -MACPYTHON_PY_PREFIX=/Library/Frameworks/Python.framework/Versions - -# ----------------------------------------------------------------------- -# Script argument parsing -# -usage() -{ - echo "Usage: - macpython-build-common - [ -h | --help ] show usage - [ -c | --cmake_options ] space-separated string of CMake options to forward to the module (e.g. \"--config-setting=cmake.define.BUILD_TESTING=OFF\") - [ -- python_versions ] build wheel for a specific python version(s). (e.g. -- 3.10 3.11)" - exit 2 -} - -PYTHON_VERSIONS="" -CMAKE_OPTIONS="" - -while (( "$#" )); do - case "$1" in - -c|--cmake_options) - CMAKE_OPTIONS="$2"; - shift 2;; - -h|--help) - usage; - break;; - --) - shift; - break;; - *) - # Parse any unrecognized arguments as python versions - PYTHON_VERSIONS="${PYTHON_VERSIONS} $1"; - shift;; - esac -done - -# Parse all arguments after "--" as python versions -PYTHON_VERSIONS="${PYTHON_VERSIONS} $@" -# Trim whitespace -PYTHON_VERSIONS=$(xargs <<< "${PYTHON_VERSIONS}") - -# Versions can be restricted by passing them in as arguments to the script -# For example, -# macpython-build-wheels.sh 3.10 -if [[ -z "${PYTHON_VERSIONS}" ]]; then - PYBINARIES=(${MACPYTHON_PY_PREFIX}/*) -else - PYBINARIES=() - for version in "$PYTHON_VERSIONS"; do - PYBINARIES+=(${MACPYTHON_PY_PREFIX}/*${version}*) - done -fi - -VENVS=() -mkdir -p ${SCRIPT_DIR}/../venvs -for PYBIN in "${PYBINARIES[@]}"; do - if [[ $(basename $PYBIN) = "Current" ]]; then - continue - fi - py_mm=$(basename ${PYBIN}) - VENV=${SCRIPT_DIR}/../venvs/${py_mm} - VENVS+=(${VENV}) -done - -# ----------------------------------------------------------------------- -# Ensure that requirements are met -brew update -brew info doxygen | grep --quiet 'Not installed' && brew install doxygen -brew info ninja | grep --quiet 'Not installed' && brew install ninja -NINJA_EXECUTABLE=$(which ninja) -brew info cmake | grep --quiet 'Not installed' && brew install cmake -CMAKE_EXECUTABLE=$(which cmake) diff --git a/scripts/macpython-build-module-deps.sh b/scripts/macpython-build-module-deps.sh deleted file mode 100644 index a74e9da7..00000000 --- a/scripts/macpython-build-module-deps.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash - -######################################################################## -# Run this script in an ITK external module directory to generate -# build artifacts for prerequisite ITK MacOS modules. -# -# Module dependencies are built in a flat directory structure regardless -# of recursive dependencies. Prerequisite sources are required to be passed -# in the order in which they should be built. -# For example, if ITKTargetModule depends on ITKTargetModuleDep2 which -# depends on ITKTargetModuleDep1, the output directory structure -# will look like this: -# -# / ITKTargetModule -# -- / ITKTargetModuleDep1 -# -- / ITKTargetModuleDep2 -# .. -# -# =========================================== -# ENVIRONMENT VARIABLES -# -# - `ITK_MODULE_PREQ`: Prerequisite ITK modules that must be built before the requested module. -# Format is `/@:/@:...`. -# For instance, `export ITK_MODULE_PREQ=InsightSoftwareConsortium/ITKMeshToPolyData@v0.10.0` -# -######################################################################## - -script_dir=$(cd $(dirname $0) || exit 1; pwd) -if [[ ! -f "${script_dir}/macpython-download-cache-and-build-module-wheels.sh" ]]; then - echo "Could not find download script to use for building module dependencies!" - exit 1 -fi - -# Temporarily update prerequisite environment variable to prevent infinite recursion. -ITK_MODULE_PREQ_TOPLEVEL=${ITK_MODULE_PREQ} -ITK_USE_LOCAL_PYTHON_TOPLEVEL=${ITK_USE_LOCAL_PYTHON} -export ITK_MODULE_PREQ="" -export ITK_USE_LOCAL_PYTHON="ON" - -######################################################################## -echo "Building ITK module dependencies: ${ITK_MODULE_PREQ_TOPLEVEL}" - -for MODULE_INFO in ${ITK_MODULE_PREQ_TOPLEVEL//:/ }; do - MODULE_ORG=`(echo ${MODULE_INFO} | cut -d'/' -f 1)` - MODULE_NAME=`(echo ${MODULE_INFO} | cut -d'@' -f 1 | cut -d'/' -f 2)` - MODULE_TAG=`(echo ${MODULE_INFO} | cut -d'@' -f 2)` - - MODULE_UPSTREAM=https://github.com/${MODULE_ORG}/${MODULE_NAME}.git - echo "Cloning from ${MODULE_UPSTREAM}" - git clone ${MODULE_UPSTREAM} - - pushd ${MODULE_NAME} - git checkout ${MODULE_TAG} - cp ${script_dir}/macpython-download-cache-and-build-module-wheels.sh . - echo "Building dependency ${MODULE_NAME}" - ./macpython-download-cache-and-build-module-wheels.sh $@ - popd - - cp ./${MODULE_NAME}/include/* include/ - find ${MODULE_NAME}/wrapping -name '*.in' -print -exec cp {} wrapping \; - find ${MODULE_NAME}/wrapping -name '*.init' -print -exec cp {} wrapping \; - find ${MODULE_NAME}/*build/*/include -type f -print -exec cp {} include \; - rm -f ./${MODULE_NAME}/ITKPythonBuilds-macosx.tar.zst -done - -# Restore environment variable -export ITK_MODULE_PREQ=${ITK_MODULE_PREQ_TOPLEVEL} -export ITK_USE_LOCAL_PYTHON=${ITK_USE_LOCAL_PYTHON_TOPLEVEL} -ITK_MODULE_PREQ_TOPLEVEL="" -ITK_USE_LOCAL_PYTHON_TOPLEVEL="" - -# Summarize disk usage for debugging -du -sh ./* | sort -hr | head -n 20 - -echo "Done building ITK external module dependencies" diff --git a/scripts/macpython-build-module-wheels.sh b/scripts/macpython-build-module-wheels.sh deleted file mode 100755 index 3c583d4d..00000000 --- a/scripts/macpython-build-module-wheels.sh +++ /dev/null @@ -1,134 +0,0 @@ -#!/usr/bin/env bash - -######################################################################## -# Run this script in an ITK external module directory to build the -# Python wheel packages for macOS for an ITK external module. -# -# ======================================================================== -# PARAMETERS -# -# Versions can be restricted by passing them in as arguments to the script. -# For example, -# -# scripts/macpython-build-module-wheels.sh 3.10 3.11 -# Shared libraries can be included in the wheel by exporting them to DYLD_LIBRARY_PATH before -# running this script. -# -# =========================================== -# ENVIRONMENT VARIABLES -# -# These variables are set with the `export` bash command before calling the script. -# For example, -# -# export DYLD_LIBRARY_PATH="/path/to/libs" -# scripts/macpython-build-module-wheels.sh 3.10 3.11 -# -# `DYLD_LIBRARY_PATH`: Shared libraries to be included in the resulting wheel. -# For instance, `export DYLD_LIBRARY_PATH="/path/to/OpenCL.so:/path/to/OpenCL.so.1.2"` -# -# `ITK_MODULE_PREQ`: Prerequisite ITK modules that must be built before the requested module. -# Format is `/@:/@:...`. -# For instance, `export ITK_MODULE_PREQ=InsightSoftwareConsortium/ITKMeshToPolyData@v0.10.0` -# -######################################################################## - - -# ----------------------------------------------------------------------- -# (Optional) Build ITK module dependencies - -script_dir=$(cd $(dirname $0) || exit 1; pwd) - -if [[ -n ${ITK_MODULE_PREQ} ]]; then - source "${script_dir}/macpython-build-module-deps.sh" -fi - -# ----------------------------------------------------------------------- -# These variables are set in common script: -# -# * CMAKE_EXECUTABLE -# * CMAKE_OPTIONS -# * MACPYTHON_PY_PREFIX -# * PYBINARIES -# * PYTHON_VERSIONS -# * NINJA_EXECUTABLE -# * SCRIPT_DIR -# * SKBUILD_DIR -# * VENVS=() - -MACPYTHON_PY_PREFIX="" -SCRIPT_DIR="" -VENVS=() - -source "${script_dir}/macpython-build-common.sh" -# ----------------------------------------------------------------------- - -VENV="${VENVS[0]}" -Python3_EXECUTABLE=${VENV}/bin/python3 -dot_clean ${VENV} -${Python3_EXECUTABLE} -m pip install --no-cache delocate -DELOCATE_LISTDEPS=${VENV}/bin/delocate-listdeps -DELOCATE_WHEEL=${VENV}/bin/delocate-wheel -DELOCATE_PATCH=${VENV}/bin/delocate-patch -# So delocate can find the libs -export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:${script_dir}/../oneTBB-prefix/lib - -# Compile wheels re-using standalone project and archive cache -for VENV in "${VENVS[@]}"; do - py_mm=$(basename ${VENV}) - Python3_EXECUTABLE=${VENV}/bin/python - Python3_INCLUDE_DIR=$( find -L ${MACPYTHON_PY_PREFIX}/${py_mm}/include -name Python.h -exec dirname {} \; ) - - echo "" - echo "Python3_EXECUTABLE:${Python3_EXECUTABLE}" - echo "Python3_INCLUDE_DIR:${Python3_INCLUDE_DIR}" - - if [[ $(arch) == "arm64" ]]; then - plat_name="macosx-15.0-arm64" - osx_target="15.0" - osx_arch="arm64" - build_path="${SCRIPT_DIR}/../ITK-${py_mm}-macosx_arm64" - else - plat_name="macosx-15.0-x86_64" - osx_target="15.0" - osx_arch="x86_64" - build_path="${SCRIPT_DIR}/../ITK-${py_mm}-macosx_x86_64" - fi - if [[ ! -z "${MACOSX_DEPLOYMENT_TARGET}" ]]; then - osx_target="${MACOSX_DEPLOYMENT_TARGET}" - fi - export MACOSX_DEPLOYMENT_TARGET=${osx_target} - - if [[ -e $PWD/requirements-dev.txt ]]; then - ${Python3_EXECUTABLE} -m pip install --upgrade -r $PWD/requirements-dev.txt - fi - itk_build_path="${build_path}" - py_minor=$(echo $py_mm | cut -d '.' -f 2) - wheel_py_api="" - if test $py_minor -ge 11; then - wheel_py_api=cp3$py_minor - fi - ${Python3_EXECUTABLE} -m build \ - --verbose \ - --wheel \ - --outdir dist \ - --no-isolation \ - --skip-dependency-check \ - --config-setting=cmake.define.CMAKE_MAKE_PROGRAM:FILEPATH=${NINJA_EXECUTABLE} \ - --config-setting=cmake.define.ITK_DIR:PATH=${itk_build_path} \ - --config-setting=cmake.define.CMAKE_INSTALL_LIBDIR:STRING=lib \ - --config-setting=cmake.define.WRAP_ITK_INSTALL_COMPONENT_IDENTIFIER:STRING=PythonWheel \ - --config-setting=cmake.define.CMAKE_OSX_DEPLOYMENT_TARGET:STRING=${osx_target} \ - --config-setting=cmake.define.CMAKE_OSX_ARCHITECTURES:STRING=${osx_arch} \ - --config-setting=cmake.define.PY_SITE_PACKAGES_PATH:PATH="." \ - --config-setting=wheel.py-api=$wheel_py_api \ - --config-setting=cmake.define.BUILD_TESTING:BOOL=OFF \ - --config-setting=cmake.define.Python3_EXECUTABLE:FILEPATH=${Python3_EXECUTABLE} \ - --config-setting=cmake.define.Python3_INCLUDE_DIR:PATH=${Python3_INCLUDE_DIR} \ - ${CMAKE_OPTIONS//'-D'/'--config-setting=cmake.define.'} \ - || exit 1 -done - -for wheel in $PWD/dist/*.whl; do - ${DELOCATE_LISTDEPS} $wheel # lists library dependencies - ${DELOCATE_WHEEL} $wheel # copies library dependencies into wheel -done diff --git a/scripts/macpython-build-tarball.sh b/scripts/macpython-build-tarball.sh deleted file mode 100755 index c4a727b4..00000000 --- a/scripts/macpython-build-tarball.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash - -# This script creates a tarball of the ITK Python package build tree. It is -# downloaded by the external module build scripts and used to build their -# Python package on GitHub CI services. - -#tbb_contents="ITKPythonPackage/oneTBB*" -tbb_contents="" -arch_postfix="" -if test $(arch) == "arm64"; then - arch_postfix="-arm64" - tbb_contents="" -fi - -pushd /Users/svc-dashboard/D/P > /dev/null -dot_clean ITKPythonPackage -tar -cf ITKPythonBuilds-macosx${arch_postfix}.tar \ - ITKPythonPackage/ITK-* \ - ${tbb_contents} \ - ITKPythonPackage/venvs \ - ITKPythonPackageRequiredExtractionDir.txt \ - ITKPythonPackage/scripts -zstd -f \ - -10 \ - -T6 \ - --long=31 \ - ./ITKPythonBuilds-macosx${arch_postfix}.tar \ - -o ./ITKPythonBuilds-macosx${arch_postfix}.tar.zst -popd > /dev/null diff --git a/scripts/macpython-build-wheels.sh b/scripts/macpython-build-wheels.sh deleted file mode 100755 index 60307e16..00000000 --- a/scripts/macpython-build-wheels.sh +++ /dev/null @@ -1,238 +0,0 @@ -#!/usr/bin/env bash - -# Run this script to build the ITK Python wheel packages for macOS. -# -# Versions can be restricted by passing them in as arguments to the script -# For example, -# -# scripts/macpython-build-wheels.sh 3.10 -# -# Shared libraries can be included in the wheel by exporting them to DYLD_LIBRARY_PATH before -# running this script. -# -# For example, -# -# export DYLD_LIBRARY_PATH="/path/to/libs" -# scripts/macpython-build-module-wheels.sh 3.10 -# - -# ----------------------------------------------------------------------- -# These variables are set in common script: -# -# * CMAKE_EXECUTABLE -# * CMAKE_OPTIONS -# * MACPYTHON_PY_PREFIX -# * PYBINARIES -# * PYTHON_VERSIONS -# * NINJA_EXECUTABLE -# * SCRIPT_DIR -# * VENVS=() - -MACPYTHON_PY_PREFIX="" -PYBINARIES="" -SCRIPT_DIR="" - -script_dir=$(cd $(dirname $0) || exit 1; pwd) -source "${script_dir}/macpython-build-common.sh" - -# ----------------------------------------------------------------------- -# Remove previous virtualenv's -rm -rf ${SCRIPT_DIR}/../venvs -# Create virtualenv's -VENVS=() -mkdir -p ${SCRIPT_DIR}/../venvs -for PYBIN in "${PYBINARIES[@]}"; do - if [[ $(basename $PYBIN) = "Current" ]]; then - continue - fi - py_mm=$(basename ${PYBIN}) - VENV=${SCRIPT_DIR}/../venvs/${py_mm} - VIRTUALENV_EXECUTABLE="${PYBIN}/bin/python3 -m venv" - ${VIRTUALENV_EXECUTABLE} ${VENV} - VENVS+=(${VENV}) -done - -VENV="${VENVS[0]}" -Python3_EXECUTABLE=${VENV}/bin/python3 -${Python3_EXECUTABLE} -m pip install --upgrade pip -${Python3_EXECUTABLE} -m pip install --no-cache delocate -DELOCATE_LISTDEPS=${VENV}/bin/delocate-listdeps -DELOCATE_WHEEL=${VENV}/bin/delocate-wheel -DELOCATE_PATCH=${VENV}/bin/delocate-patch - -build_type="Release" - -if [[ $(arch) == "arm64" ]]; then - osx_target="15.0" - osx_arch="arm64" - use_tbb="OFF" -else - osx_target="15.0" - osx_arch="x86_64" - use_tbb="OFF" -fi - -export MACOSX_DEPLOYMENT_TARGET=${osx_target} - -# Build standalone project and populate archive cache -tbb_dir=$PWD/oneTBB-prefix/lib/cmake/TBB -n_processors=$(sysctl -n hw.ncpu) -# So delocate can find the libs -export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:$PWD/oneTBB-prefix/lib -mkdir -p ITK-source -pushd ITK-source > /dev/null 2>&1 - ${CMAKE_EXECUTABLE} -DITKPythonPackage_BUILD_PYTHON:PATH=0 \ - -DITKPythonPackage_USE_TBB:BOOL=${use_tbb} \ - -G Ninja \ - -DCMAKE_BUILD_TYPE:STRING=${build_type} \ - -DCMAKE_MAKE_PROGRAM:FILEPATH=${NINJA_EXECUTABLE} \ - -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${osx_target} \ - -DCMAKE_OSX_ARCHITECTURES:STRING=${osx_arch} \ - ${SCRIPT_DIR}/../ - ${NINJA_EXECUTABLE} -j$n_processors -l$n_processors -popd > /dev/null 2>&1 - -SINGLE_WHEEL=0 - -# Compile wheels re-using standalone project and archive cache -for VENV in "${VENVS[@]}"; do - py_mm=$(basename ${VENV}) - export Python3_EXECUTABLE=${VENV}/bin/python - Python3_INCLUDE_DIR=$( find -L ${MACPYTHON_PY_PREFIX}/${py_mm}/include -name Python.h -exec dirname {} \; ) - - echo "" - echo "Python3_EXECUTABLE:${Python3_EXECUTABLE}" - echo "Python3_INCLUDE_DIR:${Python3_INCLUDE_DIR}" - - ${Python3_EXECUTABLE} -m pip install --upgrade -r ${SCRIPT_DIR}/../requirements-dev.txt - - if [[ $(arch) == "arm64" ]]; then - plat_name="macosx-15.0-arm64" - build_path="${SCRIPT_DIR}/../ITK-${py_mm}-macosx_arm64" - else - plat_name="macosx-15.0-x86_64" - build_path="${SCRIPT_DIR}/../ITK-${py_mm}-macosx_x86_64" - fi - if [[ ! -z "${MACOSX_DEPLOYMENT_TARGET}" ]]; then - osx_target="${MACOSX_DEPLOYMENT_TARGET}" - fi - source_path=${SCRIPT_DIR}/../ITK-source/ITK - PYPROJECT_CONFIGURE="${script_dir}/pyproject_configure.py" - - # Clean up previous invocations - rm -rf ${build_path} - - if [[ ${SINGLE_WHEEL} == 1 ]]; then - - echo "#" - echo "# Build single ITK wheel" - echo "#" - - # Configure pyproject.toml - ${Python3_EXECUTABLE} ${PYPROJECT_CONFIGURE} "itk" - # Generate wheel - ${Python3_EXECUTABLE} -m build \ - --verbose \ - --wheel \ - --outdir dist \ - --no-isolation \ - --skip-dependency-check \ - --config-setting=cmake.define.CMAKE_MAKE_PROGRAM:FILEPATH=${NINJA_EXECUTABLE} \ - --config-setting=cmake.define.ITK_SOURCE_DIR:PATH=${source_path} \ - --config-setting=cmake.define.ITK_BINARY_DIR:PATH=${build_path} \ - --config-setting=cmake.define.CMAKE_OSX_DEPLOYMENT_TARGET:STRING=${osx_target} \ - --config-setting=cmake.define.CMAKE_OSX_ARCHITECTURES:STRING=${osx_arch} \ - --config-setting=cmake.define.Python3_EXECUTABLE:FILEPATH=${Python3_EXECUTABLE} \ - --config-setting=cmake.define.Python3_INCLUDE_DIR:PATH=${Python3_INCLUDE_DIR} \ - --config-setting=cmake.define.Module_ITKTBB:BOOL=${use_tbb} \ - --config-setting=cmake.define.TBB_DIR:PATH=${tbb_dir} \ - . \ - ${CMAKE_OPTIONS} - - else - - echo "#" - echo "# Build multiple ITK wheels" - echo "#" - - # Build ITK python - ( - mkdir -p ${build_path} \ - && cd ${build_path} \ - && cmake \ - -DCMAKE_BUILD_TYPE:STRING=${build_type} \ - -DITK_SOURCE_DIR:PATH=${source_path} \ - -DITK_BINARY_DIR:PATH=${build_path} \ - -DBUILD_TESTING:BOOL=OFF \ - -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${osx_target} \ - -DCMAKE_OSX_ARCHITECTURES:STRING=${osx_arch} \ - -DITK_WRAP_unsigned_short:BOOL=ON \ - -DITK_WRAP_double:BOOL=ON \ - -DITK_WRAP_complex_double:BOOL=ON \ - -DITK_WRAP_IMAGE_DIMS:STRING="2;3;4" \ - -DPython3_EXECUTABLE:FILEPATH=${Python3_EXECUTABLE} \ - -DPython3_INCLUDE_DIR:PATH=${Python3_INCLUDE_DIR} \ - -DWRAP_ITK_INSTALL_COMPONENT_IDENTIFIER:STRING=PythonWheel \ - -DWRAP_ITK_INSTALL_COMPONENT_PER_MODULE:BOOL=ON \ - "-DPY_SITE_PACKAGES_PATH:PATH=." \ - -DITK_LEGACY_SILENT:BOOL=ON \ - -DITK_WRAP_PYTHON:BOOL=ON \ - -DITK_WRAP_DOC:BOOL=ON \ - -DModule_ITKTBB:BOOL=${use_tbb} \ - -DTBB_DIR:PATH=${tbb_dir} \ - ${CMAKE_OPTIONS} \ - -G Ninja \ - ${source_path} \ - && ninja -j$n_processors -l$n_processors \ - || exit 1 - ) - - wheel_names=$(cat ${SCRIPT_DIR}/WHEEL_NAMES.txt) - for wheel_name in ${wheel_names}; do - # Configure pyproject.toml - ${Python3_EXECUTABLE} ${PYPROJECT_CONFIGURE} ${wheel_name} - # Generate wheel - ${Python3_EXECUTABLE} -m build \ - --verbose \ - --wheel \ - --outdir dist \ - --no-isolation \ - --skip-dependency-check \ - --config-setting=cmake.define.ITK_SOURCE_DIR:PATH=${source_path} \ - --config-setting=cmake.define.ITK_BINARY_DIR:PATH=${build_path} \ - --config-setting=cmake.define.CMAKE_OSX_DEPLOYMENT_TARGET:STRING=${osx_target} \ - --config-setting=cmake.define.CMAKE_OSX_ARCHITECTURES:STRING=${osx_arch} \ - --config-setting=cmake.define.ITKPythonPackage_USE_TBB:BOOL=${use_tbb} \ - --config-setting=cmake.define.ITKPythonPackage_ITK_BINARY_REUSE:BOOL=ON \ - --config-setting=cmake.define.ITKPythonPackage_WHEEL_NAME:STRING=${wheel_name} \ - --config-setting=cmake.define.Python3_EXECUTABLE:FILEPATH=${Python3_EXECUTABLE} \ - --config-setting=cmake.define.Python3_INCLUDE_DIR:PATH=${Python3_INCLUDE_DIR} \ - . \ - ${CMAKE_OPTIONS} \ - || exit 1 - done - - fi - - # Remove unnecessary files for building against ITK - find ${build_path} -name '*.cpp' -delete -o -name '*.xml' -delete - rm -rf ${build_path}/Wrapping/Generators/castxml* - find ${build_path} -name '*.o' -delete -done - -if [[ $(arch) != "arm64" ]]; then - for wheel in dist/itk_*.whl; do - echo "Delocating $wheel" - ${DELOCATE_LISTDEPS} $wheel # lists library dependencies - ${DELOCATE_WHEEL} $wheel # copies library dependencies into wheel - done -fi - -for VENV in "${VENVS[@]}"; do - ${VENV}/bin/pip install numpy - ${VENV}/bin/pip install itk --no-cache-dir --no-index -f ${SCRIPT_DIR}/../dist - (cd $HOME && ${VENV}/bin/python -c 'import itk;') - (cd $HOME && ${VENV}/bin/python -c 'import itk; image = itk.Image[itk.UC, 2].New()') - (cd $HOME && ${VENV}/bin/python -c 'import itkConfig; itkConfig.LazyLoading = False; import itk;') - (cd $HOME && ${VENV}/bin/python ${SCRIPT_DIR}/../docs/code/test.py ) -done diff --git a/scripts/macpython-download-cache-and-build-module-wheels.sh b/scripts/macpython-download-cache-and-build-module-wheels.sh index 297e827d..f0189ab7 100755 --- a/scripts/macpython-download-cache-and-build-module-wheels.sh +++ b/scripts/macpython-download-cache-and-build-module-wheels.sh @@ -10,93 +10,187 @@ # Versions can be restricted by passing them in as arguments to the script. # For example, # -# scripts/macpython-download-cache-and-build-module-wheels.sh 3.9 3.11 +# scripts/macpython-download-cache-and-build-module-wheels.sh 3.11 # # Shared libraries can be included in the wheel by setting DYLD_LIBRARY_PATH before # running this script. -# + # =========================================== -# ENVIRONMENT VARIABLES +# ENVIRONMENT VARIABLES: ITK_GIT_TAG ITKPYTHONPACKAGE_ORG ITK_USE_LOCAL_PYTHON ITK_PACKAGE_VERSION # # These variables are set with the `export` bash command before calling the script. # For example, -# -# export DYLD_LIBRARY_PATH="/path/to/libs" -# -# `ITK_PACKAGE_VERSION`: ITKPythonBuilds archive tag to use for ITK build artifacts. -# See https://github.com/InsightSoftwareConsortium/ITKPythonBuilds for available tags. -# For instance, `export ITK_PACKAGE_VERSION=v5.4.0`. -# -# `ITKPYTHONPACKAGE_ORG`: Github organization for fetching ITKPythonPackage build scripts. -# -# `ITKPYTHONPACKAGE_TAG`: ITKPythonPackage tag for fetching build scripts. -# -# `ITK_USE_LOCAL_PYTHON`: Determine how to get Python framework for build. -# - If empty, Python frameworks will be fetched from python.org -# - If not empty, frameworks already on machine will be used without fetching. +# scripts/macpython-build-module-wheels.sh 3.10 3.11 # ######################################################################## +DEFAULT_MODULE_DIRECTORY=$( + cd "$(dirname "$0")" || exit 1 + pwd +) +# if not specified, use the current directory for MODULE_SRC_DIRECTORY +MODULE_SRC_DIRECTORY=${MODULE_SRC_DIRECTORY:=${DEFAULT_MODULE_DIRECTORY}} -# Install dependencies -brew update -brew install --quiet zstd aria2 gnu-tar doxygen ninja -brew upgrade --quiet cmake rustup +usage() { + echo "Usage: + macpython-download-cache-and-build-module-wheels + [ -h | --help ] show usage + [ -c | --cmake_options ] space-delimited string containing CMake options to forward to the module (e.g. \"-DBUILD_TESTING=OFF\") + [ python_version ] build wheel for a specific python version. (e.g. 3.11)" + exit 2 +} -if [[ $(arch) == "arm64" ]]; then - tarball_arch="-arm64" -else - tarball_arch="" +CMAKE_OPTIONS="" +while [ $# -gt 0 ]; do + case "$1" in + -h | --help) usage ;; + -c | --cmake_options) + CMAKE_OPTIONS="$2" + shift 2 + ;; + --) + shift + break + ;; + *) + break + ;; + esac +done + +if [ -z "${ITK_PACKAGE_VERSION}" ]; then + echo "MUST SET ITK_PACKAGE_VERSION BEFORE RUNNING THIS SCRIPT" + exit 1 +fi + +# For backwards compatibility when the ITK_GIT_TAG was required to match the ITK_PACKAGE_VERSION +ITK_GIT_TAG=${ITK_GIT_TAG:=${ITK_PACKAGE_VERSION}} + +DASHBOARD_BUILD_DIRECTORY=${DASHBOARD_BUILD_DIRECTORY:=/Users/svc-dashboard/D/P} +ITKPYTHONPACKAGE_ORG=${ITKPYTHONPACKAGE_ORG:=InsightSoftwareConsortium} +# Run build scripts +if [ -z "${NO_SUDO}" ] || [ "${NO_SUDO}" -ne 1 ]; then + sudo_exec=sudo fi -# Fetch ITKPythonBuilds archive containing ITK build artifacts -rm -fr ITKPythonPackage -echo "Fetching https://github.com/InsightSoftwareConsortium/ITKPythonBuilds/releases/download/${ITK_PACKAGE_VERSION:=v5.4.0}/ITKPythonBuilds-macosx${tarball_arch}.tar.zst" -if [[ ! -f ITKPythonBuilds-macosx${tarball_arch}.tar.zst ]]; then - aria2c -c --file-allocation=none -o ITKPythonBuilds-macosx${tarball_arch}.tar.zst -s 10 -x 10 https://github.com/InsightSoftwareConsortium/ITKPythonBuilds/releases/download/${ITK_PACKAGE_VERSION:=v5.4.0}/ITKPythonBuilds-macosx${tarball_arch}.tar.zst +if [ ! -d "${DASHBOARD_BUILD_DIRECTORY}" ]; then + ${sudo_exec} mkdir -p "${DASHBOARD_BUILD_DIRECTORY}" && ${sudo_exec} chown "$UID:$GID" "${DASHBOARD_BUILD_DIRECTORY}" fi -unzstd --long=31 ITKPythonBuilds-macosx${tarball_arch}.tar.zst -o ITKPythonBuilds-macosx${tarball_arch}.tar -PATH="$(dirname $(brew list gnu-tar | grep gnubin)):$PATH" -gtar xf ITKPythonBuilds-macosx${tarball_arch}.tar --warning=no-unknown-keyword --checkpoint=10000 --checkpoint-action=dot \ - ITKPythonPackage/ITK-source \ - ITKPythonPackageRequiredExtractionDir.txt \ - ITKPythonPackage/scripts - -# Extract subdirectories specific to the compiled python versions -args=( "$@" ) -source ITKPythonPackage/scripts/macpython-build-common.sh -for version in "$PYTHON_VERSIONS"; do - gtar xf ITKPythonBuilds-macosx${tarball_arch}.tar --warning=no-unknown-keyword --checkpoint=10000 --checkpoint-action=dot \ - --wildcards "ITKPythonPackage/ITK-${version}-macosx*" \ - "ITKPythonPackage/venvs/${version}" +cd "${DASHBOARD_BUILD_DIRECTORY}" || exit + +# ----------------------------------------------------------------------- +# Check for conda/pixi-provided ITK (libitk-wrapping package). +# When available, skip the tarball download entirely. + +_conda_itk_dir="" +for _prefix_var in CONDA_PREFIX PIXI_ENVIRONMENT_DIR; do + _prefix="${!_prefix_var:-}" + if [ -n "${_prefix}" ]; then + for _candidate in "${_prefix}"/lib/cmake/ITK-*; do + if [ -f "${_candidate}/ITKConfig.cmake" ]; then + _conda_itk_dir="${_candidate}" + echo "Detected conda-installed ITK at ${_conda_itk_dir} (via \$${_prefix_var})" + break 2 + fi + done + fi done -rm ITKPythonBuilds-macosx${tarball_arch}.tar +if [ -n "${_conda_itk_dir}" ]; then + echo "Using conda-installed ITK; skipping tarball download." +else + # NOTE: download phase will install pixi in the DASHBOARD_BUILD_DIRECTORY (which is separate from the pixi + # environment used by ITKPythonPackage). + export PIXI_HOME=${DASHBOARD_BUILD_DIRECTORY}/.pixi + if [ ! -f "${PIXI_HOME}/.pixi/bin/pixi" ]; then + # Install pixi + curl -fsSL https://pixi.sh/install.sh | sh + # These are the tools needed for cross platform downloads of the ITK build caches stored in https://github.com/InsightSoftwareConsortium/ITKPythonBuilds + pixi global install zstd + pixi global install aria2 + pixi global install gnu-tar + pixi global install git + pixi global install rsync + fi + export PATH="${PIXI_HOME}/bin:$PATH" -# Optional: Update build scripts -if [[ -n ${ITKPYTHONPACKAGE_TAG} ]]; then - echo "Updating build scripts to ${ITKPYTHONPACKAGE_ORG:=InsightSoftwareConsortium}/ITKPythonPackage@${ITKPYTHONPACKAGE_TAG}" - git clone "https://github.com/${ITKPYTHONPACKAGE_ORG}/ITKPythonPackage.git" "IPP-tmp" - pushd IPP-tmp/ - git checkout "${ITKPYTHONPACKAGE_TAG}" - git status - popd + tarball_arch="-$(arch)" + TARBALL_NAME="ITKPythonBuilds-macosx${tarball_arch}.tar" - rm -rf ITKPythonPackage/scripts/ - cp -r IPP-tmp/scripts ITKPythonPackage/ - rm -rf IPP-tmp/ -fi + if [[ ! -f ${TARBALL_NAME}.zst ]]; then + echo "Local ITK cache tarball file not found..." + # Fetch ITKPythonBuilds archive containing ITK build artifacts + echo "Fetching https://github.com/InsightSoftwareConsortium/ITKPythonBuilds/releases/download/${ITK_PACKAGE_VERSION}/ITKPythonBuilds-macosx${tarball_arch}.tar.zst" + if ! curl -L "https://github.com/InsightSoftwareConsortium/ITKPythonBuilds/releases/download/${ITK_PACKAGE_VERSION}/ITKPythonBuilds-macosx${tarball_arch}.tar.zst" -O; then + echo "FAILED Download:" + echo "curl -L https://github.com/InsightSoftwareConsortium/ITKPythonBuilds/releases/download/${ITK_PACKAGE_VERSION}/${TARBALL_NAME}.zst -O" + exit 1 + fi + fi -# Run build scripts -sudo mkdir -p /Users/svc-dashboard/D/P && sudo chown $UID:$GID /Users/svc-dashboard/D/P -if [[ ! -d /Users/svc-dashboard/D/P/ITKPythonPackage ]]; then - mv ITKPythonPackage /Users/svc-dashboard/D/P/ -fi + if [[ ! -f ./${TARBALL_NAME}.zst ]]; then + echo "ERROR: can not find required binary './${TARBALL_NAME}.zst'" + exit 255 + fi -# Optionally install baseline Python versions -if [[ ! ${ITK_USE_LOCAL_PYTHON} ]]; then - echo "Fetching Python frameworks" - sudo rm -rf /Library/Frameworks/Python.framework/Versions/* - /Users/svc-dashboard/D/P/ITKPythonPackage/scripts/macpython-install-python.sh + local_compress_tarball_name=${DASHBOARD_BUILD_DIRECTORY}/ITKPythonBuilds-macosx${tarball_arch}.tar.zst + if [[ ! -f ${local_compress_tarball_name} ]]; then + aria2c -c --file-allocation=none -d "$(dirname "${local_compress_tarball_name}")" -o "$(basename "${local_compress_tarball_name}")" -s 10 -x 10 "https://github.com/InsightSoftwareConsortium/ITKPythonBuilds/releases/download/${ITK_PACKAGE_VERSION}/ITKPythonBuilds-macosx${tarball_arch}.tar.zst" + fi + local_tarball_name=${DASHBOARD_BUILD_DIRECTORY}/ITKPythonBuilds-macosx${tarball_arch}.tar + unzstd --long=31 "${local_compress_tarball_name}" -o "${local_tarball_name}" + # Find GNU tar (gtar from pixi or brew) for reliable extraction + if command -v gtar >/dev/null 2>&1; then + TAR_CMD=gtar + TAR_FLAGS=(--warning=no-unknown-keyword --checkpoint=10000 --checkpoint-action=dot) + elif tar --version 2>/dev/null | grep -q "GNU tar"; then + TAR_CMD=tar + TAR_FLAGS=(--warning=no-unknown-keyword --checkpoint=10000 --checkpoint-action=dot) + else + TAR_CMD=tar + TAR_FLAGS=() + fi + "${TAR_CMD}" xf "${local_tarball_name}" "${TAR_FLAGS[@]}" + rm "${local_tarball_name}" + + # Optional: Update build scripts + if [[ -n ${ITKPYTHONPACKAGE_TAG} ]]; then + echo "Updating build scripts to ${ITKPYTHONPACKAGE_ORG}/ITKPythonPackage@${ITKPYTHONPACKAGE_TAG}" + local_clone_ipp=${DASHBOARD_BUILD_DIRECTORY}/ITKPythonPackage_${ITKPYTHONPACKAGE_TAG} + if [ ! -d "${local_clone_ipp}/.git" ]; then + git clone "https://github.com/${ITKPYTHONPACKAGE_ORG}/ITKPythonPackage.git" "${local_clone_ipp}" + fi + pushd "${local_clone_ipp}" || exit + git checkout "${ITKPYTHONPACKAGE_TAG}" + git reset "origin/${ITKPYTHONPACKAGE_TAG}" --hard + git status + popd || exit + rsync -av "${local_clone_ipp}/" "${DASHBOARD_BUILD_DIRECTORY}/ITKPythonPackage/" + fi fi echo "Building module wheels" -/Users/svc-dashboard/D/P/ITKPythonPackage/scripts/macpython-build-module-wheels.sh "${args[@]}" +cd "${DASHBOARD_BUILD_DIRECTORY}/ITKPythonPackage" || exit +echo "$@" +for py_indicator in "$@"; do + # The following line is to convert "py3.11|py311|cp311|3.11" -> py311 normalized form + py_squashed_numeric=$(echo "${py_indicator}" | sed 's/py//g' | sed 's/cp//g' | sed 's/\.//g') + pyenv=py${py_squashed_numeric} + pixi run -e "macosx-${pyenv}" -- python \ + "${DASHBOARD_BUILD_DIRECTORY}/ITKPythonPackage/scripts/build_wheels.py" \ + --platform-env "macosx-${pyenv}" \ + --lib-paths '' '' \ + --module-source-dir "${MODULE_SRC_DIRECTORY}" \ + --module-dependencies-root-dir "${DASHBOARD_BUILD_DIRECTORY}/MODULE_DEPENDENCIES" \ + --itk-module-deps "${ITK_MODULE_PREQ}" \ + --no-build-itk-tarball-cache \ + --build-dir-root "${DASHBOARD_BUILD_DIRECTORY}/ITKPythonPackage-build" \ + --manylinux-version '' \ + --itk-git-tag "${ITK_GIT_TAG}" \ + --itk-source-dir "${DASHBOARD_BUILD_DIRECTORY}/ITKPythonPackage-build/ITK" \ + --itk-package-version "${ITK_PACKAGE_VERSION}" \ + --no-use-sudo \ + --no-use-ccache \ + --skip-itk-build \ + --skip-itk-wheel-build \ + ${CMAKE_OPTIONS:+-- ${CMAKE_OPTIONS}} + #Let this be automatically selected --macosx-deployment-target 10.7 \ +done diff --git a/scripts/macpython-install-python.sh b/scripts/macpython-install-python.sh deleted file mode 100755 index 70a57b7a..00000000 --- a/scripts/macpython-install-python.sh +++ /dev/null @@ -1,423 +0,0 @@ -#!/usr/bin/env bash - -# Download and install Python.org's MacPython and install Pip - -# Adapted from https://github.com/matthew-brett/multibuild -# osx_utils.sh -#The multibuild package, including all examples, code snippets and attached -#documentation is covered by the 2-clause BSD license. - - #Copyright (c) 2013-2016, Matt Terry and Matthew Brett; all rights - #reserved. - - #Redistribution and use in source and binary forms, with or without - #modification, are permitted provided that the following conditions are - #met: - - #1. Redistributions of source code must retain the above copyright notice, - #this list of conditions and the following disclaimer. - - #2. Redistributions in binary form must reproduce the above copyright - #notice, this list of conditions and the following disclaimer in the - #documentation and/or other materials provided with the distribution. - - #THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - #IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - #THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - #PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - #CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - #EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - #PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - #PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - #LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - #NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - #SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -set -x - -MACPYTHON_URL=https://www.python.org/ftp/python -MACPYTHON_PY_PREFIX=/Library/Frameworks/Python.framework/Versions -MACPYTHON_DEFAULT_OSX="10.6" -MB_PYTHON_OSX_VER=${MB_PYTHON_OSX_VER:-$MACPYTHON_DEFAULT_OSX} -GET_PIP_URL=https://bootstrap.pypa.io/get-pip.py -DOWNLOADS_SDIR=downloads -WORKING_SDIR=working - -# As of 2 November 2022 - latest Python of each version with binary download -# available. -# See: https://www.python.org/downloads/mac-osx/ -LATEST_2p7=2.7.18 -LATEST_3p5=3.5.4 -LATEST_3p6=3.6.8 -LATEST_3p7=3.7.9 -LATEST_3p8=3.8.10 -LATEST_3p9=3.9.13 -LATEST_3p10=3.10.11 -LATEST_3p11=3.11.4 -LATEST_3p12=3.12.0 - - -function check_python { - if [ -z "$PYTHON_EXE" ]; then - echo "PYTHON_EXE variable not defined" - exit 1 - fi -} - -function check_pip { - if [ -z "$PIP_CMD" ]; then - echo "PIP_CMD variable not defined" - exit 1 - fi -} - -function check_var { - if [ -z "$1" ]; then - echo "required variable not defined" - exit 1 - fi -} - -function get_py_digit { - check_python - $PYTHON_EXE -c "import sys; print(sys.version_info[0])" -} - -function get_py_mm { - check_python - $PYTHON_EXE -c "import sys; print('{0}.{1}'.format(*sys.version_info[0:2]))" -} - -function get_py_mm_nodot { - check_python - $PYTHON_EXE -c "import sys; print('{0}{1}'.format(*sys.version_info[0:2]))" -} - -function get_py_prefix { - check_python - $PYTHON_EXE -c "import sys; print(sys.prefix)" -} - -function fill_pyver { - # Convert major or major.minor format to major.minor.micro - # - # Hence: - # 2 -> 2.7.11 (depending on LATEST_2p7 value) - # 2.7 -> 2.7.11 (depending on LATEST_2p7 value) - local ver=$1 - check_var $ver - if [[ $ver =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then - # Major.minor.micro format already - echo $ver - elif [ $ver == 2 ] || [ $ver == "2.7" ]; then - echo $LATEST_2p7 - elif [ $ver == 3 ] || [ $ver == "3.11" ]; then - echo $LATEST_3p11 - elif [ $ver == "3.12" ]; then - echo $LATEST_3p12 - elif [ $ver == "3.10" ]; then - echo $LATEST_3p10 - elif [ $ver == "3.9" ]; then - echo $LATEST_3p9 - elif [ $ver == "3.8" ]; then - echo $LATEST_3p8 - elif [ $ver == "3.7" ]; then - echo $LATEST_3p7 - elif [ $ver == "3.6" ]; then - echo $LATEST_3p6 - elif [ $ver == "3.5" ]; then - echo $LATEST_3p5 - else - echo "Can't fill version $ver" 1>&2 - exit 1 - fi -} - -function macpython_sdk_list_for_version { - # return a list of SDK targets supported for a given CPython version - # Parameters - # $py_version (python version in major.minor.extra format) - # eg - # macpython_sdks_for_version 2.7.15 - # >> 10.6 10.9 - local _ver=$(fill_pyver $1) - local _major=${_ver%%.*} - local _return - - if [ "${PLAT}" = "arm64" ]; then - _return="11.0" - elif [ "$_major" -eq "2" ]; then - [ $(lex_ver $_ver) -lt $(lex_ver 2.7.18) ] && _return="10.6" - [ $(lex_ver $_ver) -ge $(lex_ver 2.7.15) ] && _return="$_return 10.9" - elif [ "$_major" -eq "3" ]; then - [ $(lex_ver $_ver) -lt $(lex_ver 3.8) ] && _return="10.6" - [ $(lex_ver $_ver) -ge $(lex_ver 3.6.5) ] && _return="$_return 10.9" - else - echo "Error version=${_ver}, expecting 2.x or 3.x" 1>&2 - exit 1 - fi - echo $_return -} - -function macpython_sdk_for_version { - # assumes the output of macpython_sdk_list_for_version is a list - # of SDK versions XX.Y in sorted order, eg "10.6 10.9" or "10.9" - echo $(macpython_sdk_list_for_version $1) | awk -F' ' '{print $NF}' -} - -function pyinst_ext_for_version { - # echo "pkg" or "dmg" depending on the passed Python version - # Parameters - # $py_version (python version in major.minor.extra format) - # - # Earlier Python installers are .dmg, later are .pkg. - local py_version=$1 - check_var $py_version - py_version=$(fill_pyver $py_version) - local py_0=${py_version:0:1} - if [ $py_0 -eq 2 ]; then - if [ "$(lex_ver $py_version)" -ge "$(lex_ver 2.7.9)" ]; then - echo "pkg" - else - echo "dmg" - fi - elif [ $py_0 -ge 3 ]; then - echo "pkg" - fi -} - -function pyinst_fname_for_version { - # echo filename for OSX installer file given Python and minimum - # macOS versions - # Parameters - # $py_version (Python version in major.minor.extra format) - # $py_osx_ver: {major.minor | not defined} - # if defined, the minimum macOS SDK version that Python is - # built for, eg: "10.6" or "10.9", if not defined, infers - # this from $py_version using macpython_sdk_for_version - local py_version=$1 - local py_osx_ver=${2:-$(macpython_sdk_for_version $py_version)} - local inst_ext=$(pyinst_ext_for_version $py_version) - if [ "${PLAT:-}" == "arm64" ] || [ "${PLAT:-}" == "universal2" ]; then - if [ "$py_version" == "3.9.1" ]; then - echo "python-${py_version}-macos11.0.${inst_ext}" - else - echo "python-${py_version}-macos11.${inst_ext}" - fi - else - if [ "$py_version" == "3.7.9" ]; then - echo "python-${py_version}-macosx${py_osx_ver}.${inst_ext}" - else - echo "python-${py_version}-macos${py_osx_ver}.${inst_ext}" - fi - fi -} - -function get_macpython_arch { - # echo arch (e.g. intel or x86_64), extracted from the distutils platform tag - # Parameters - # $distutils_plat PEP425 style platform tag, or if not provided, calls - # the function get_distutils_platform, provided by - # common_utils.sh. Fails if this is not a mac platform - # - # Note: MUST only be called after the version of Python used to build the - # target wheel has been installed and is on the path - local distutils_plat=${1:-$(get_distutils_platform)} - if [[ $distutils_plat =~ macosx-(1[0-9]\.[0-9]+)-(.*) ]]; then - echo ${BASH_REMATCH[2]} - else - echo "Error parsing macOS distutils platform '$distutils_plat'" - exit 1 - fi -} - -function get_macpython_osx_ver { - # echo minimum macOS version (e.g. 10.9) from the distutils platform tag - # Parameters - # $distutils_plat PEP425 style platform tag, or if not provided, calls - # the function get_distutils_platform, provided by - # common_utils.sh. Fails if this is not a mac platform - # - # Note: MUST only be called after the version of Python used to build the - # target wheel has been installed and is on the path - local distutils_plat=${1:-$(get_distutils_platform)} - if [[ $distutils_plat =~ macosx-(1[0-9]\.[0-9]+)-(.*) ]]; then - echo ${BASH_REMATCH[1]} - else - echo "Error parsing macOS distutils platform '$distutils_plat'" - exit 1 - fi -} - -function macpython_arch_for_version { - # echo arch (intel or x86_64) that a version of Python is expected - # to be built for - # Parameters - # $py_ver Python version, in the format (major.minor.patch) for - # CPython, or pypy-(major.minor) for PyPy - # $py_osx_ver minimum macOS version the target Python is built for - # (major.minor) - local py_ver=$1 - local py_osx_ver=${2:-$MB_PYTHON_OSX_VER} - check_var $1 - if [[ $(macpython_impl_for_version $py_ver) == "cp" ]]; then - if [[ "$py_osx_ver" == "10.6" ]]; then - echo "intel" - elif [[ "$py_osx_ver" == "10.9" ]]; then - echo "x86_64" - else - echo "Unexpected CPython macOS version: ${py_osx_ver}, supported values: 10.6 and 10.9" - exit 1 - fi - else - echo "x86_64" - fi -} - -function macpython_impl_for_version { - # echo Python implementation (cp for CPython, pp for PyPy) given a - # suitably formatted version string - # Parameters: - # $version : [implementation-]major[.minor[.patch]] - # Python implementation, e.g. "3.6" for CPython or - # "pypy-5.4" for PyPy - local version=$1 - check_var $1 - if [[ "$version" =~ ^pypy ]]; then - echo pp - elif [[ "$version" =~ ([0-9\.]+) ]]; then - echo cp - else - echo "config error: Issue parsing this implementation in install_python:" - echo " version=$version" - exit 1 - fi -} - -function strip_macpython_ver_prefix { - # strip any implementation prefix from a Python version string - # Parameters: - # $version : [implementation-]major[.minor[.patch]] - # Python implementation, e.g. "3.6" for CPython or - # "pypy-5.4" for PyPy - local version=$1 - check_var $1 - if [[ "$version" =~ (pypy-)?([0-9\.]+) ]]; then - echo ${BASH_REMATCH[2]} - fi -} - -function install_macpython { - # Install Python and set $PYTHON_EXE to the installed executable - # Parameters: - # $version : [implementation-]major[.minor[.patch]] - # The Python implementation to install, e.g. "3.6", "pypy-5.4" or "pypy3.6-7.2" - # $py_osx_ver: {major.minor | not defined} - # if defined, the macOS version that CPython is built for, e.g. - # "10.6" or "10.9". Ignored for PyPy - local version=$1 - local py_osx_ver=$2 - local impl=$(macpython_impl_for_version $version) - if [[ "$impl" == "pp" ]]; then - install_pypy $version - elif [[ "$impl" == "cp" ]]; then - local stripped_ver=$(strip_macpython_ver_prefix $version) - install_mac_cpython $stripped_ver $py_osx_ver - else - echo "Unexpected Python impl: ${impl}" - exit 1 - fi -} - -function install_mac_cpython { - # Installs Python.org Python - # Parameters - # $py_version - # Version given in major or major.minor or major.minor.micro e.g - # "3" or "3.7" or "3.7.1". - # $py_osx_ver - # {major.minor | not defined} - # if defined, the macOS version that Python is built for, e.g. - # "10.6" or "10.9" - # sets $PYTHON_EXE variable to Python executable - local py_version=$(fill_pyver $1) - local py_osx_ver=$2 - #local py_stripped=$(strip_ver_suffix $py_version) - local py_stripped=$py_version - local py_inst=$(pyinst_fname_for_version $py_version $py_osx_ver) - local inst_path=$DOWNLOADS_SDIR/$py_inst - local retval="" - mkdir -p $DOWNLOADS_SDIR - # exit early on curl errors, but don't let it exit the shell - curl -f $MACPYTHON_URL/$py_stripped/${py_inst} > $inst_path || retval=$? - if [ ${retval:-0} -ne 0 ]; then - echo "Python download failed! Check ${py_inst} exists on the server." - exit $retval - fi - - if [ "${py_inst: -3}" == "dmg" ]; then - hdiutil attach $inst_path -mountpoint /Volumes/Python - inst_path=/Volumes/Python/Python.mpkg - fi - sudo installer -pkg $inst_path -target / - local py_mm=${py_version%.*} - PYTHON_EXE=$MACPYTHON_PY_PREFIX/$py_mm/bin/python$py_mm - # Install certificates for Python 3.6 - local inst_cmd="/Applications/Python ${py_mm}/Install Certificates.command" - if [ -e "$inst_cmd" ]; then - sh "$inst_cmd" - fi - PIP_CMD="$MACPYTHON_PY_PREFIX/$py_mm/bin/python$py_mm -m pip" - $PIP_CMD install --upgrade pip - export PIP_CMD -} - -function install_virtualenv { - # Generic install of virtualenv - # Installs virtualenv into python given by $PYTHON_EXE - # Assumes virtualenv will be installed into same directory as $PYTHON_EXE - check_pip - # Travis VMS install virtualenv for system python by default - force - # install even if installed already - $PIP_CMD install virtualenv --ignore-installed - check_python - VIRTUALENV_CMD="$(dirname $PYTHON_EXE)/virtualenv" - export VIRTUALENV_CMD -} - -function make_workon_venv { - # Make a virtualenv in given directory ('venv' default) - # Set $PYTHON_EXE, $PIP_CMD to virtualenv versions - # Parameter $venv_dir - # directory for virtualenv - local venv_dir=$1 - if [ -z "$venv_dir" ]; then - venv_dir="venv" - fi - venv_dir=`abspath $venv_dir` - check_python - $PYTHON_EXE -m virtualenv $venv_dir - PYTHON_EXE=$venv_dir/bin/python - PIP_CMD=$venv_dir/bin/pip -} - -# Remove previous versions -#echo "Remove and update Python files at ${MACPYTHON_FRAMEWORK}" -#sudo rm -rf ${MACPYTHON_FRAMEWORK} - -if test "$(arch)" == "arm64"; then - echo "we are arm" - PLAT=arm64 - for pyversion in $LATEST_3p10 $LATEST_3p11; do - install_macpython $pyversion 11 - install_virtualenv - done -else - # Deployment target requirements: - # * 10.9: Python 3.7 - # * 11: Python >= 3.8 - for pyversion in $LATEST_3p10 $LATEST_3p11; do - install_macpython $pyversion 11 - install_virtualenv - done -fi diff --git a/scripts/make_tarballs.sh b/scripts/make_tarballs.sh new file mode 100755 index 00000000..cdd93d6e --- /dev/null +++ b/scripts/make_tarballs.sh @@ -0,0 +1,120 @@ +#!/usr/bin/env bash +# NOTES: Building tarballs requires specific pathing for supporting github CI +# workflows + +script_dir=$( + cd "$(dirname "$0")" || exit 1 + pwd +) +_ipp_dir=$(dirname "${script_dir}") + +# If args are given, use them. Otherwise use default python environments +pyenvs=("${@:-py310 py311}") + +# Otherwise process mac and linux based on uname + +# Need to explicitly request to --build-itk-tarball-cache +BUILD_WHEELS_EXTRA_FLAGS=("--build-itk-tarball-cache") +if [ -z "${ITK_GIT_TAG}" ]; then + DEFAULT_ITK_GIT_TAG=v6.0b02 + echo "=============================================================================" + echo "=============================================================================" + for _ in x x x x x x x x x x x x x x x x x x x x x x x x x x x x x; do + echo "===== WARNING: ITK_GIT_TAG not set, so defaulting to ${DEFAULT_ITK_GIT_TAG}" + done + echo "=============================================================================" + echo "=============================================================================" +fi +ITK_GIT_TAG=${ITK_GIT_TAG:=${DEFAULT_ITK_GIT_TAG}} + +## -- +# -- +# -- +# -- +# Short circuit builds to use dockcross if MANYLINUX_VERSION is requested +if [ -n "${MANYLINUX_VERSION}" ]; then + BUILD_WHEELS_EXTRA_FLAGS="${BUILD_WHEELS_EXTRA_FLAGS[*]}" \ + ITK_GIT_TAG=${ITK_GIT_TAG} \ + MANYLINUX_VERSION=${MANYLINUX_VERSION} \ + bash "${_ipp_dir}/scripts/dockcross-manylinux-build-wheels.sh" \ + "${pyenvs[@]}" + exit $? +fi + +## -- +# -- +# -- +# -- +case "$(uname -s)" in +Darwin) + PLATFORM_PREFIX="macosx" + DASHBOARD_BUILD_DIRECTORY=${DASHBOARD_BUILD_DIRECTORY:=/Users/svc-dashboard/D/P} + ;; +Linux) + PLATFORM_PREFIX="linux" + DASHBOARD_BUILD_DIRECTORY=${DASHBOARD_BUILD_DIRECTORY:=/work} + ;; + # POSIX build env NOT SUPPORTED for windows, Needs to be done in a .ps1 shell + # MINGW*|MSYS*|CYGWIN*) + # PLATFORM_PREFIX="windows" + # DASHBOARD_BUILD_DIRECTORY="C:\P" + # ;; +*) + echo "Unsupported platform: $(uname -s)" + exit 1 + ;; +esac + +# Required environment variables +required_vars=( + ITK_GIT_TAG + PLATFORM_PREFIX + DASHBOARD_BUILD_DIRECTORY + +) + +# Sanity Validation loop +_missing_required=0 +for v in "${required_vars[@]}"; do + if [ -z "${!v:-}" ]; then + _missing_required=1 + echo "ERROR: Required environment variable '$v' is not set or empty." + fi +done +if [ "${_missing_required}" -ne 0 ]; then + exit 1 +fi +unset _missing_required + +if [ ! -d "${DASHBOARD_BUILD_DIRECTORY}" ]; then + # This is the expected directory for the cache, It may require creation with administrator credentials + mkdir -p "${DASHBOARD_BUILD_DIRECTORY}" +fi +if [ "${script_dir}" != "${DASHBOARD_BUILD_DIRECTORY}/ITKPythonPackage/scripts" ]; then + echo "ERROR: Github CI requires rigid directory structure, you may substitute the ITKPythonPackage organization if testing" + echo " RUN: cd ${DASHBOARD_BUILD_DIRECTORY}" + echo " RUN: git clone git@github.com:${ITKPYTHONPACKAGE_ORG}/ITKPythonPackage.git ${DASHBOARD_BUILD_DIRECTORY}/ITKPythonPackage" + echo " FOR DEVELOPMENT RUN: git checkout python_based_build_scripts" + echo " RUN: ${DASHBOARD_BUILD_DIRECTORY}/ITKPythonPackage/scripts/make_tarballs.sh" + exit 1 +fi + +export PIXI_HOME=${DASHBOARD_BUILD_DIRECTORY}/.pixi +if [ ! -f "${PIXI_HOME}/bin/pixi" ]; then + #PIXI INSTALL + if [ ! -f "${PIXI_HOME}/bin/pixi" ]; then + curl -fsSL https://pixi.sh/install.sh | sh + export PATH="${PIXI_HOME}/bin:$PATH" + fi +fi + +for pyenv in "${pyenvs[@]}"; do + cd "${DASHBOARD_BUILD_DIRECTORY}/ITKPythonPackage" || exit + "${PIXI_HOME}/bin/pixi" run -e "${PLATFORM_PREFIX}-${pyenv}" \ + python3 "${DASHBOARD_BUILD_DIRECTORY}/ITKPythonPackage/scripts/build_wheels.py" \ + --platform-env "${PLATFORM_PREFIX}-${pyenv}" \ + --build-dir-root "${DASHBOARD_BUILD_DIRECTORY}/ITKPythonPackage-build" \ + --itk-source-dir "${DASHBOARD_BUILD_DIRECTORY}/ITKPythonPackage-build/ITK" \ + --itk-git-tag "${ITK_GIT_TAG}" \ + "${BUILD_WHEELS_EXTRA_FLAGS[@]}" +done diff --git a/scripts/make_windows_zip.ps1 b/scripts/make_windows_zip.ps1 new file mode 100644 index 00000000..fe69477a --- /dev/null +++ b/scripts/make_windows_zip.ps1 @@ -0,0 +1,157 @@ +######################################################################## +# Build ITK Python wheel tarballs (build cache) on Windows. +# +# This is the Windows PowerShell equivalent of make_tarballs.sh. +# POSIX shell is not supported for this workflow on Windows. +# +# This script builds the ITK core cache only — it has no knowledge of +# external modules. Module-specific flags (--module-source-dir, +# --module-dependencies-root-dir, --itk-module-deps, --lib-paths) are +# intentionally absent; they belong only in the module wheel build script. +# +# Directory names are intentionally kept short to avoid Windows MAX_PATH +# issues during deep CMake/compiler builds. Everything lives under one +# root directory (C:\BDR) so no build artifacts are scattered at C:\: +# ITKPythonPackage -> C:\BDR\IPP (scripts clone) +# ITK source -> C:\BDR\ITK (ITK git checkout) +# build root -> C:\BDR (build_wheels.py root; cached build lands at C:\BDR\build\ITK-windows-...) +# +# This script MUST be run from the canonical location: +# C:\BDR\IPP\scripts\make_tarballs.ps1 +# +# Typical usage: +# > $env:ITK_GIT_TAG = "v6.0b02" +# > .\make_tarballs.ps1 +# +# Restrict to specific python versions by passing them as arguments: +# > .\make_tarballs.ps1 py311 +# +# ----------------------------------------------------------------------- +# Environment variables: +# +# `$env:ITK_GIT_TAG` +# ITK git tag to build from. Falls back to v6.0b02 with loud warnings +# if unset, matching the bash script behaviour. +# +######################################################################## +param ( + [Parameter(ValueFromRemainingArguments)] + [string[]]$pyenvs +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +# Resolve python environments +if (-not $pyenvs -or $pyenvs.Count -eq 0) { + $pyenvs = @("py310", "py311") +} +echo "Building for python environments: $($pyenvs -join ', ')" + +# Resolve ITK_GIT_TAG — loud warning if unset, matching bash behaviour +$DEFAULT_ITK_GIT_TAG = "v6.0b02" +if (-not $env:ITK_GIT_TAG) { + $warningLine = "===== WARNING: ITK_GIT_TAG not set, so defaulting to $DEFAULT_ITK_GIT_TAG" + echo "=============================================================================" + 1..29 | ForEach-Object { echo $warningLine } + echo "=============================================================================" + $env:ITK_GIT_TAG = $DEFAULT_ITK_GIT_TAG +} +$ITK_GIT_TAG = $env:ITK_GIT_TAG +echo "ITK_GIT_TAG : $ITK_GIT_TAG" + +# Compute paths from this script's location. +# Everything is contained under C:\BDR to keep all build artifacts in one +# place and avoid spreading directories across the drive root. +# +# C:\BDR\ <- $BDR (single root for all build content) +# C:\BDR\IPP\scripts\ <- $ScriptsDir (this file) +# C:\BDR\IPP\ <- $IPPDir (ITKPythonPackage clone) +# C:\BDR\ITK\ <- $ItkSourceDir (ITK git checkout) +# C:\BDR\ <- $BuildDirRoot (build root; cached build lands at C:\BDR\build\ITK-windows-...) +# C:\BDR\.pixi\ <- pixi home +$BDR = "C:\BDR" +$ScriptsDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$IPPDir = Split-Path -Parent $ScriptsDir +$BuildScript = Join-Path $ScriptsDir "build_wheels.py" +$ItkSourceDir = Join-Path $BDR "ITK" +$BuildDirRoot = $BDR + +echo "BDR : $BDR" +echo "IPPDir : $IPPDir" +echo "ScriptsDir : $ScriptsDir" +echo "ItkSourceDir : $ItkSourceDir" +echo "BuildDirRoot : $BuildDirRoot" + +# Validate script is running from the expected canonical location +$ExpectedScriptsDir = Join-Path $BDR "IPP\scripts" +if ($ScriptsDir -ne $ExpectedScriptsDir) { + Write-Error @" +ERROR: GitHub CI requires a rigid directory structure. +Script found at : $ScriptsDir +Expected location: $ExpectedScriptsDir + + RUN: cd $BDR + RUN: git clone git@github.com:/ITKPythonPackage.git $BDR\IPP + FOR DEVELOPMENT: git checkout python_based_build_scripts + RUN: $ExpectedScriptsDir\make_windows_zip.ps1 +"@ + exit 1 +} + +if (-not (Test-Path -LiteralPath $BuildScript)) { + throw "build_wheels.py not found at: $BuildScript" +} + +# Create BDR if it doesn't exist +# (may require administrator credentials on a fresh machine) +if (-not (Test-Path -LiteralPath $BDR)) { + echo "Creating directory: $BDR" + New-Item -ItemType Directory -Path $BDR -Force | Out-Null +} + +# Install pixi if not already present. +# Python, Doxygen, and all build tools are provided by the pixi environment. +$env:PIXI_HOME = "$BDR\.pixi" +if (-not (Test-Path "$env:PIXI_HOME\bin\pixi.exe")) { + echo "Installing pixi..." + Invoke-WebRequest -Uri "https://pixi.sh/install.ps1" -OutFile "install-pixi.ps1" + powershell -ExecutionPolicy Bypass -File "install-pixi.ps1" +} +$env:Path = "$env:PIXI_HOME\bin;$env:Path" + +# Build each requested python environment. +# Push-Location/finally ensures we always restore the caller's directory. +Push-Location $IPPDir +try { + foreach ($pyenv in $pyenvs) { + # Normalise any of: py311 / py3.11 / cp311 / 3.11 -> py311 + $pySquashed = $pyenv -replace 'py|cp|\.', '' + $pyenv = "py$pySquashed" + $platformEnv = "windows-$pyenv" + + echo "" + echo "========================================================" + echo "Building cache for platform env: $platformEnv" + echo "========================================================" + + pixi run -e $platformEnv python $BuildScript ` + --platform-env $platformEnv ` + --build-itk-tarball-cache ` + --build-dir-root $BuildDirRoot ` + --itk-source-dir $ItkSourceDir ` + --itk-git-tag $ITK_GIT_TAG ` + --no-use-sudo ` + --no-use-ccache + + if ($LASTEXITCODE -ne 0) { + throw "build_wheels.py failed for $platformEnv (exit code $LASTEXITCODE)" + } + } +} +finally { + Pop-Location +} + +echo "" +echo "All tarball builds completed successfully." diff --git a/scripts/oci_exe.sh b/scripts/oci_exe.sh deleted file mode 100644 index f3d7cffb..00000000 --- a/scripts/oci_exe.sh +++ /dev/null @@ -1,23 +0,0 @@ -function ociExe() { - # Check for OCI_EXE environmental variable - if [[ -n "$OCI_EXE" && -x "$OCI_EXE" ]]; then - echo "$OCI_EXE" - return - fi - - # Check for podman executable - if which podman > /dev/null 2>&1; then - echo "podman" - return - fi - - # Check for docker executable - if which docker > /dev/null 2>&1; then - echo "docker" - return - fi - - # If none of the above exist, return nothing - echo "Could not find podman or docker executable" >&2 - exit 1 -} \ No newline at end of file diff --git a/scripts/publish_tarball_cache.py b/scripts/publish_tarball_cache.py new file mode 100644 index 00000000..5ea1e350 --- /dev/null +++ b/scripts/publish_tarball_cache.py @@ -0,0 +1,126 @@ +"""Upload ITK build cache tarballs to a GitHub Release. + +Usage: + pixi run -e publish publish-tarball-cache --itk-package-version v6.0b02 + pixi run -e publish publish-tarball-cache --itk-package-version v6.0b02 --create-release + +Authentication: + Set the GH_TOKEN environment variable, or run `gh auth login` beforehand. + +Cache files are expected at {build-dir-root}/../ITKPythonBuilds-*.tar.zst (POSIX) +or {build-dir-root}/ITKPythonBuilds-*.zip (Windows). +""" + +import argparse +import subprocess +import sys +from pathlib import Path + +ITKPYTHONBUILDS_REPO = "InsightSoftwareConsortium/ITKPythonBuilds" + + +def main() -> int: + parser = argparse.ArgumentParser( + description="Upload tarball caches to a GitHub Release on ITKPythonBuilds" + ) + parser.add_argument( + "--build-dir-root", + type=Path, + default=Path(__file__).resolve().parent.parent.parent + / "ITKPythonPackage-build", + help="Root of the build directory (tarballs are in its parent). Default: ../ITKPythonPackage-build", + ) + parser.add_argument( + "--itk-package-version", + required=True, + help="Release tag name, e.g. v6.0b02", + ) + parser.add_argument( + "--repo", + default=ITKPYTHONBUILDS_REPO, + help=f"GitHub repository for the release (default: {ITKPYTHONBUILDS_REPO})", + ) + parser.add_argument( + "--create-release", + action="store_true", + help="Create the GitHub release if it does not already exist", + ) + args = parser.parse_args() + + build_directory = Path(args.build_dir_root) + tarball_dir = build_directory.parent + # POSIX builds produce .tar.zst, Windows builds produce .zip in the build directory + tarballs = sorted( + list(tarball_dir.glob("ITKPythonBuilds-*.tar.zst")) + + list( + build_directory.glob("ITKPythonBuilds-*.zip") + ) # Windows builds will be in the build directory + ) + + if not tarballs: + print( + f"Error: No ITKPythonBuilds-*.tar.zst or .zip files found in {tarball_dir} or {build_directory}.", + file=sys.stderr, + ) + return 1 + + print( + f"Found {len(tarballs)} cache file(s) in {tarball_dir} and {build_directory}:" + ) + for tb in tarballs: + size_mb = tb.stat().st_size / (1024 * 1024) + print(f" {tb.name} ({size_mb:.1f} MB)") + + tag = args.itk_package_version + + # Check if the release exists + result = subprocess.run( + ["gh", "release", "view", tag, "--repo", args.repo], + capture_output=True, + text=True, + ) + if result.returncode != 0: + if args.create_release: + print(f"\nCreating release '{tag}' on {args.repo}...") + create_result = subprocess.run( + [ + "gh", + "release", + "create", + tag, + "--repo", + args.repo, + "--title", + tag, + "--notes", + f"ITK Python build cache for {tag}", + ], + ) + if create_result.returncode != 0: + print("Error: Failed to create release.", file=sys.stderr) + return 1 + else: + print( + f"Error: Failed to create release with code: {result.returncode}\nwith message:\n{result.stderr}", + file=sys.stderr, + ) + return 1 + else: + print(f"\nRelease '{tag}' exists on {args.repo}.") + + # Upload each tarball (--clobber replaces existing assets with the same name) + for tb in tarballs: + print(f"Uploading {tb.name}...") + upload_result = subprocess.run( + ["gh", "release", "upload", tag, str(tb), "--repo", args.repo, "--clobber"], + ) + if upload_result.returncode != 0: + print(f"Error: Failed to upload {tb.name}.", file=sys.stderr) + return 1 + + print("\nAll uploads complete.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/publish_wheels.py b/scripts/publish_wheels.py new file mode 100644 index 00000000..e3e8f5f0 --- /dev/null +++ b/scripts/publish_wheels.py @@ -0,0 +1,93 @@ +"""Upload ITK Python wheels to PyPI or TestPyPI. + +Usage: + pixi run -e publish publish-wheels --dist-directory /path/to/dist + pixi run -e publish publish-wheels --dist-directory /path/to/dist --test + +Authentication: + Set TWINE_USERNAME and TWINE_PASSWORD environment variables. + For token-based auth: + TWINE_USERNAME=__token__ + TWINE_PASSWORD=pypi- + + Alternatively, configure ~/.pypirc (see .pypirc.example in the repo root). +""" + +import argparse +import subprocess +import sys +from pathlib import Path + +TESTPYPI_URL = "https://test.pypi.org/legacy/" + + +def main() -> int: + parser = argparse.ArgumentParser( + description="Upload ITK wheels to PyPI or TestPyPI" + ) + parser.add_argument( + "--dist-directory", + type=Path, + default=Path(__file__).resolve().parent.parent.parent + / "ITKPythonPackage-build/dist", + help="Root of the build dist directory containing dist/*.whl (default: ../ITKPythonPackage-build/dist)", + ) + parser.add_argument( + "--test", + action="store_true", + help="Upload to TestPyPI instead of production PyPI", + ) + parser.add_argument( + "--repository-url", + type=str, + default=None, + help="Custom repository URL (overrides --test)", + ) + parser.add_argument( + "--skip-existing", + action="store_true", + help="Skip wheels that have already been uploaded", + ) + args = parser.parse_args() + + dist_dir = args.dist_directory + wheels = sorted(dist_dir.glob("*.whl")) + + if not wheels: + print(f"Error: No .whl files found in {dist_dir}", file=sys.stderr) + return 1 + + print(f"Found {len(wheels)} wheel(s) in {dist_dir}:") + for w in wheels: + print(f" {w.name}") + + # Validate wheel metadata before uploading + print("\nRunning twine check...") + result = subprocess.run( + ["twine", "check", *(str(w) for w in wheels)], + ) + if result.returncode != 0: + print( + "Error: twine check failed. Fix metadata issues before uploading.", + file=sys.stderr, + ) + return 1 + + # Build upload command + cmd = ["twine", "upload"] + if args.repository_url: + cmd += ["--repository-url", args.repository_url] + elif args.test: + cmd += ["--repository-url", TESTPYPI_URL] + if args.skip_existing: + cmd.append("--skip-existing") + cmd += [str(w) for w in wheels] + + target = args.repository_url or (TESTPYPI_URL if args.test else "PyPI") + print(f"\nUploading to {target}...") + result = subprocess.run(cmd) + return result.returncode + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/pyproject.toml.in b/scripts/pyproject.toml.in index 1ed3b17b..f583cc7e 100644 --- a/scripts/pyproject.toml.in +++ b/scripts/pyproject.toml.in @@ -9,7 +9,7 @@ name = "@PYPROJECT_NAME@" version = "@PYPROJECT_VERSION@" description = "@PYPROJECT_DESCRIPTION@" -readme = "ITK-source/ITK/README.md" +readme = "@ITK_SOURCE_README@" license = {file = "LICENSE"} authors = [ { name = "Insight Software Consortium", email = "community@itk.org" }, @@ -39,7 +39,7 @@ classifiers = [ "Topic :: Scientific/Engineering :: Medical Science Apps.", "Topic :: Software Development :: Libraries", ] -requires-python = ">=3.9" +requires-python = ">=3.10" dependencies = [ @PYPROJECT_DEPENDENCIES@ ] @@ -96,7 +96,7 @@ sdist.include = ["CMakeLists.txt", "cmake/*.cmake", "README.md", "itkVersion.py" sdist.exclude = ["scripts"] # The Python tags. The default (empty string) will use the default Python -# version. You can also set this to "cp37" to enable the CPython 3.7+ Stable ABI +# version. You can also set this to "cp310" to enable the CPython 3.10+ Stable ABI # / Limited API (only on CPython and if the version is sufficient, otherwise # this has no effect). Or you can set it to "py3" or "py2.py3" to ignore Python # ABI compatibility. The ABI tag is inferred from this tag. diff --git a/scripts/pyproject_configure.py b/scripts/pyproject_configure.py index 55ba9c2c..19b669a2 100755 --- a/scripts/pyproject_configure.py +++ b/scripts/pyproject_configure.py @@ -1,55 +1,48 @@ #!/usr/bin/env python - -"""CLI allowing to configure ``pyproject.toml`` found in ``ITKPythonPackage`` -source tree. - -Different version of ``pyproject.toml`` can be generated based on the value -of the `wheel_name` positional parameter. - -Usage:: - - pyproject_configure.py [-h] [--output-dir OUTPUT_DIR] wheel_name - - positional arguments: - wheel_name - - optional arguments: - -h, --help show this help message and exit - --output-dir OUTPUT_DIR - Output directory for configured 'pyproject.toml' - (default: /work) - - -Accepted values for `wheel_name` are ``itk`` and all values read from -``WHEEL_NAMES.txt``. -""" - import argparse import os import re +import shutil import sys +from pathlib import Path -sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) - -PARAMETER_OPTION_DEFAULTS = { - "indent": 0, - "newline_if_set": False, - "newline_indent": 0, - "remove_line_if_empty": False, -} - -PARAMETER_OPTIONS = { - "PYPROJECT_PY_MODULES": {"indent": 8, "newline_if_set": True, "newline_indent": 4}, - "PYPROJECT_DEPENDENCIES": {"indent": 8, "remove_line_if_empty": True}, -} +from packaging.version import Version +from wheel_builder_utils import read_env_file def parameter_option(key, option): - """Return value of `option` associated with parameter `key`. - - If no option is found in `PARAMETER_OPTIONS`, default value from - `PARAMETER_OPTION_DEFAULTS` is returned. + """Return a formatting option for a template parameter. + + Parameters + ---------- + key : str + Template parameter name (e.g. ``'PYPROJECT_PY_MODULES'``). + option : str + Option to look up (``'indent'``, ``'newline_if_set'``, + ``'newline_indent'``, or ``'remove_line_if_empty'``). + + Returns + ------- + int or bool + The option value from ``PARAMETER_OPTIONS`` if defined, + otherwise the default from ``PARAMETER_OPTION_DEFAULTS``. """ + PARAMETER_OPTION_DEFAULTS = { + "indent": 0, + "newline_if_set": False, + "newline_indent": 0, + "remove_line_if_empty": False, + } + + PARAMETER_OPTIONS = { + "PYPROJECT_PY_MODULES": { + "indent": 8, + "newline_if_set": True, + "newline_indent": 4, + }, + "PYPROJECT_DEPENDENCIES": {"indent": 8, "remove_line_if_empty": True}, + } + default = PARAMETER_OPTION_DEFAULTS.get(option) if key not in PARAMETER_OPTIONS.keys(): return default @@ -58,13 +51,24 @@ def parameter_option(key, option): # Copied from scikit-ci/ci/utils.py def indent(text, prefix, predicate=None): - """Adds 'prefix' to the beginning of selected lines in 'text'. - If 'predicate' is provided, 'prefix' will only be added to the lines - where 'predicate(line)' is True. If 'predicate' is not provided, - it will default to adding 'prefix' to all non-empty lines that do not - consist solely of whitespace characters. - - Copied from textwrap.py available in python 3 (cpython/cpython@a2d2bef) + """Add *prefix* to the beginning of selected lines in *text*. + + Copied from ``textwrap.py`` (cpython/cpython@a2d2bef). + + Parameters + ---------- + text : str + The multiline string to indent. + prefix : str + String prepended to each selected line. + predicate : callable, optional + Called with each line; *prefix* is added only when it returns + True. Defaults to adding *prefix* to all non-blank lines. + + Returns + ------- + str + The indented text. """ if predicate is None: @@ -73,29 +77,51 @@ def predicate(line): def prefixed_lines(): for line in text.splitlines(True): - yield (prefix + line if predicate(line) else line) + yield prefix + line if predicate(line) else line return "".join(prefixed_lines()) def list_to_str(list_, newline=True): + """Join a list of strings as quoted, comma-separated items. + + Parameters + ---------- + list_ : list[str] + Items to format. + newline : bool, optional + Use newline separators when True, spaces when False. + + Returns + ------- + str + Formatted string like ``'"a",\\n"b"'``. + """ sep = ", " if newline: sep = ",\n" - return sep.join(['"%s"' % item for item in list_]) + return sep.join([f'"{item}"' for item in list_]) def configure(template_file, parameters, output_file): - """Configure `template_file` into `output_file` given a dictionary of - `parameters`. + """Substitute ``@KEY@`` placeholders in *template_file* and write *output_file*. + + Parameters + ---------- + template_file : str or Path + Input template containing ``@KEY@`` placeholders. + parameters : dict[str, str] + Mapping of placeholder names to substitution values. + output_file : str or Path + Destination path for the configured file. """ updated_lines = [] - with open(template_file, "r") as file_: + with open(template_file) as file_: lines = file_.readlines() for line in lines: append = True for key in parameters.keys(): - value = parameters[key].strip() + value = str(parameters[key]).strip() if ( key in line and not value @@ -107,8 +133,10 @@ def configure(template_file, parameters, output_file): value = indent(value, block_indent) newline_indent = " " * parameter_option(key, "newline_indent") if value.strip() and parameter_option(key, "newline_if_set"): - value = "\n%s\n%s" % (value, newline_indent) - line = line.replace("@%s@" % key, value) + value = f"\n{value}\n{newline_indent}" + line = line.replace(f"@{key}@", value) + # Windows paths need to have backslashes escaped preserved in writing of files + line = line.replace("\\", "\\\\") if append: updated_lines.append(line) @@ -117,16 +145,56 @@ def configure(template_file, parameters, output_file): def from_group_to_wheel(group): - return "itk-%s" % group.lower() + """Convert an ITK group name to its wheel package name. + Parameters + ---------- + group : str + ITK group name (e.g. ``'Core'``, ``'Filtering'``). -def update_wheel_pyproject_toml_parameters(): - global PYPROJECT_PY_PARAMETERS - for wheel_name in get_wheel_names(): - params = dict(ITK_PYPROJECT_PY_PARAMETERS) + Returns + ------- + str + Wheel name like ``'itk-core'``. + """ + return f"itk-{group.lower()}" + + +def update_wheel_pyproject_toml_parameters( + base_params: dict, + package_env_config: dict, + SCRIPT_NAME: str, + wheel_names: list, + wheel_dependencies: dict, +): + """Build a mapping of wheel name to ``pyproject.toml`` template parameters. + + This is a pure transformation and does not mutate global state. + + Parameters + ---------- + base_params : dict + Shared base parameters common to all wheels. + package_env_config : dict + Build environment configuration (ITK paths, versions, etc.). + SCRIPT_NAME : str + Name of the calling script, embedded in the generator field. + wheel_names : list[str] + Ordered list of wheel package names to generate parameters for. + wheel_dependencies : dict[str, list[str]] + Mapping from wheel name to its dependency list. + + Returns + ------- + dict[str, dict] + ``{wheel_name: parameters_dict}`` for each wheel. + """ + PYPROJECT_PY_PARAMETERS = {} + for wheel_name in wheel_names: + params = dict(base_params) # generator - params["PYPROJECT_GENERATOR"] = "python %s '%s'" % (SCRIPT_NAME, wheel_name) + params["PYPROJECT_GENERATOR"] = f"python {SCRIPT_NAME} '{wheel_name}'" # name if wheel_name == "itk-meta": @@ -182,18 +250,21 @@ def update_wheel_pyproject_toml_parameters(): # cmake_args params["PYPROJECT_CMAKE_ARGS"] = list_to_str( [ + f"-DITK_SOURCE_DIR={package_env_config['ITK_SOURCE_DIR']}", + f"-DITK_GIT_TAG:STRING={package_env_config['ITK_GIT_TAG']}", + f"-DITK_PACKAGE_VERSION:STRING={package_env_config['ITK_PACKAGE_VERSION']}", "-DITK_WRAP_unsigned_short:BOOL=ON", "-DITK_WRAP_double:BOOL=ON", "-DITK_WRAP_complex_double:BOOL=ON", "-DITK_WRAP_IMAGE_DIMS:STRING=2;3;4", "-DITK_WRAP_DOC:BOOL=ON", - "-DITKPythonPackage_WHEEL_NAME:STRING=%s" % wheel_name, + f"-DITKPythonPackage_WHEEL_NAME:STRING={wheel_name}", ], True, ) # install_requires - wheel_depends = get_wheel_dependencies()[wheel_name] + wheel_depends = list(wheel_dependencies[wheel_name]) # py_modules if wheel_name != "itk-core": @@ -205,35 +276,63 @@ def update_wheel_pyproject_toml_parameters(): PYPROJECT_PY_PARAMETERS[wheel_name] = params + return PYPROJECT_PY_PARAMETERS -def get_wheel_names(): - with open(os.path.join(SCRIPT_DIR, "WHEEL_NAMES.txt"), "r") as _file: - return [wheel_name.strip() for wheel_name in _file.readlines()] +def get_wheel_names(IPP_BuildWheelsSupport_DIR: str): + """Read the ordered list of wheel names from ``WHEEL_NAMES.txt``. -def get_version(): - from itkVersion import get_versions + Parameters + ---------- + IPP_BuildWheelsSupport_DIR : str + Directory containing ``WHEEL_NAMES.txt``. - version = get_versions()["package-version"] - return version + Returns + ------- + list[str] + Stripped wheel names, one per line. + """ + with open(os.path.join(IPP_BuildWheelsSupport_DIR, "WHEEL_NAMES.txt")) as _file: + return [wheel_name.strip() for wheel_name in _file.readlines()] def get_py_api(): - import sys + """Return the stable ABI tag for the running Python, or empty string. + Returns + ------- + str + A tag like ``'cp311'`` for Python >= 3.11, or ``''`` otherwise. + """ + # Return empty for Python < 3.11, otherwise a cp tag like 'cp311' if sys.version_info < (3, 11): return "" - else: - return "cp" + str(sys.version_info.major) + str(sys.version_info.minor) + return f"cp{sys.version_info.major}{sys.version_info.minor}" -def get_wheel_dependencies(): - """Return a dictionary of ITK wheel dependencies.""" +def get_wheel_dependencies(SCRIPT_DIR: str, version: str, wheel_names: list): + """Parse ITK CMake files to build a wheel dependency graph. + + Parameters + ---------- + SCRIPT_DIR : str + Path to the ``scripts/`` directory. + version : str + PEP 440 version string pinned in each dependency. + wheel_names : list[str] + All known wheel names; used to build the ``itk-meta`` entry. + + Returns + ------- + dict[str, list[str]] + Mapping of wheel name to its list of pinned dependencies. + """ all_depends = {} regex_group_depends = r"set\s*\(\s*ITK\_GROUP\_([a-zA-Z0-9\_\-]+)\_DEPENDS\s*([a-zA-Z0-9\_\-\s]*)\s*" # noqa: E501 pattern = re.compile(regex_group_depends) - version = get_version() - with open(os.path.join(SCRIPT_DIR, "..", "CMakeLists.txt"), "r") as file_: + with open( + os.path.join(SCRIPT_DIR, "..", "cmake/ITKPythonPackage_BuildWheels.cmake") + ) as file_: for line in file_.readlines(): match = re.search(pattern, line) if not match: @@ -246,86 +345,226 @@ def get_wheel_dependencies(): all_depends[wheel] = _wheel_depends all_depends["itk-meta"] = [ wheel_name + "==" + version - for wheel_name in get_wheel_names() + for wheel_name in wheel_names if wheel_name != "itk-meta" ] all_depends["itk-meta"].append("numpy") return all_depends -SCRIPT_DIR = os.path.dirname(__file__) -SCRIPT_NAME = os.path.basename(__file__) - -ITK_PYPROJECT_PY_PARAMETERS = { - "PYPROJECT_GENERATOR": "python %s '%s'" % (SCRIPT_NAME, "itk"), - "PYPROJECT_NAME": r"itk", - "PYPROJECT_VERSION": get_version(), - "PYPROJECT_CMAKE_ARGS": r"", - "PYPROJECT_PY_API": get_py_api(), - "PYPROJECT_PLATLIB": r"true", - "PYPROJECT_PY_MODULES": list_to_str( - [ - "itkBase", - "itkConfig", - "itkExtras", - "itkHelpers", - "itkLazy", - "itkTemplate", - "itkTypes", - "itkVersion", - "itkBuildOptions", - ] - ), - "PYPROJECT_DOWNLOAD_URL": r"https://github.com/InsightSoftwareConsortium/ITK/releases", - "PYPROJECT_DESCRIPTION": r"ITK is an open-source toolkit for multidimensional image analysis", # noqa: E501 - "PYPROJECT_LONG_DESCRIPTION": r"ITK is an open-source, cross-platform library that " - "provides developers with an extensive suite of software " - "tools for image analysis. Developed through extreme " - "programming methodologies, ITK employs leading-edge " - "algorithms for registering and segmenting " - "multidimensional scientific images.", - "PYPROJECT_EXTRA_KEYWORDS": r'"scientific", "medical", "image", "imaging"', - "PYPROJECT_DEPENDENCIES": r"", -} - -PYPROJECT_PY_PARAMETERS = {"itk": ITK_PYPROJECT_PY_PARAMETERS} - -update_wheel_pyproject_toml_parameters() +def build_base_pyproject_parameters( + package_env_config: dict, SCRIPT_NAME: str, itk_package_version: str +): + """Return the base ``pyproject.toml`` template parameters for ITK. + + Parameters + ---------- + package_env_config : dict + Build environment configuration. + SCRIPT_NAME : str + Name of the calling script. + itk_package_version : str + PEP 440 version string for the ITK packages. + + Returns + ------- + dict[str, str] + Base parameter mapping shared across all wheel configurations. + """ + ITK_SOURCE_README: str = os.path.join( + package_env_config["ITK_SOURCE_DIR"], "README.md" + ) + return { + "PYPROJECT_GENERATOR": f"python {SCRIPT_NAME} 'itk'", + "PYPROJECT_NAME": r"itk", + "PYPROJECT_VERSION": itk_package_version, + "PYPROJECT_CMAKE_ARGS": r"", + "PYPROJECT_PY_API": get_py_api(), + "PYPROJECT_PLATLIB": r"true", + "ITK_SOURCE_DIR": package_env_config["ITK_SOURCE_DIR"], + "ITK_SOURCE_README": ITK_SOURCE_README, + "PYPROJECT_PY_MODULES": list_to_str( + [ + "itkBase", + "itkConfig", + "itkExtras", + "itkHelpers", + "itkLazy", + "itkTemplate", + "itkTypes", + "itkVersion", + "itkBuildOptions", + ] + ), + "PYPROJECT_DOWNLOAD_URL": r"https://github.com/InsightSoftwareConsortium/ITK/releases", + "PYPROJECT_DESCRIPTION": r"ITK is an open-source toolkit for multidimensional image analysis", # noqa: E501 + "PYPROJECT_LONG_DESCRIPTION": r"ITK is an open-source, cross-platform library that " + "provides developers with an extensive suite of software " + "tools for image analysis. Developed through extreme " + "programming methodologies, ITK employs leading-edge " + "algorithms for registering and segmenting " + "multidimensional scientific images.", + "PYPROJECT_EXTRA_KEYWORDS": r'"scientific", "medical", "image", "imaging"', + "PYPROJECT_DEPENDENCIES": r"", + } def main(): - # Defaults - default_output_dir = os.path.abspath(os.path.join(SCRIPT_DIR, "..")) - # Parse arguments + SCRIPT_DIR = os.path.dirname(__file__) parser = argparse.ArgumentParser( - formatter_class=argparse.ArgumentDefaultsHelpFormatter + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + description="""CLI allowing to configure ``pyproject.toml`` found in the `` ITKPythonPackage `` +source tree. + +Different versions of ``pyproject.toml`` can be generated based on the value +of the `wheel_name` positional parameter. + +Usage:: + + pyproject_configure.py [-h] [--output-dir OUTPUT_DIR] wheel_name + + positional arguments: + wheel_name + + optional arguments: + -h, --help show this help message and exit + --output-dir OUTPUT_DIR + Output directory for configured 'pyproject.toml' + (default: /work) + +Accepted values for `wheel_name` are ``itk`` and all values read from +``WHEEL_NAMES.txt``. +""", ) parser.add_argument("wheel_name") parser.add_argument( "--output-dir", type=str, help="Output directory for configured 'pyproject.toml'", - default=default_output_dir, + default=os.path.abspath(os.path.join(SCRIPT_DIR, "..")), + ) + parser.add_argument( + "--build-dir-root", + type=str, + default=f"{SCRIPT_DIR}/../", + help="The root of the build resources.", ) args = parser.parse_args() - template = os.path.join(SCRIPT_DIR, "pyproject.toml.in") - if args.wheel_name not in PYPROJECT_PY_PARAMETERS.keys(): - print("Unknown wheel name '%s'" % args.wheel_name) + print(f"Reading configuration settings from {args.env_file}") + package_env_config = read_env_file(args.env_file, args.build_dir_root) + + configure_one_pyproject_file( + SCRIPT_DIR, package_env_config, args.output_dir, args.wheel_name + ) + + +def configure_one_pyproject_file( + SCRIPT_DIR: str | bytes, package_env_config, output_dir, wheel_name: str = "itk" +): + """Generate a configured ``pyproject.toml`` for a single wheel. + + Parameters + ---------- + SCRIPT_DIR : str or bytes + Path to the ``scripts/`` directory containing templates. + package_env_config : dict + Build environment configuration. + output_dir : str or Path + Directory where ``pyproject.toml`` will be written. + wheel_name : str, optional + Which wheel to configure (default ``'itk'``). + """ + # Version needs to be python PEP 440 compliant (no leading v) + PEP440_VERSION: str = package_env_config["ITK_PACKAGE_VERSION"].removeprefix("v") + try: + Version( + PEP440_VERSION + ) # Raise InvalidVersion exception if not PEP 440 compliant + except ValueError: + print(f"Invalid PEP 440 version: {PEP440_VERSION}") + sys.exit(1) + + # Resolve script information locally + + IPP_BuildWheelsSupport_DIR = os.path.join(SCRIPT_DIR, "..", "BuildWheelsSupport") + SCRIPT_NAME = os.path.basename(__file__) + # Write itkVersion.py file to report ITK version in python. + write_itkVersion_py(Path(output_dir) / "itkVersion.py", PEP440_VERSION) + # Copy LICENSE file needed for each wheel + shutil.copy(Path(IPP_BuildWheelsSupport_DIR) / "LICENSE", output_dir) + + base_params = build_base_pyproject_parameters( + package_env_config, SCRIPT_NAME, PEP440_VERSION + ) + + wheel_names = get_wheel_names(IPP_BuildWheelsSupport_DIR) + wheel_dependencies = get_wheel_dependencies( + SCRIPT_DIR, base_params["PYPROJECT_VERSION"], wheel_names + ) + + PYPROJECT_PY_PARAMETERS = {"itk": dict(base_params)} + PYPROJECT_PY_PARAMETERS.update( + update_wheel_pyproject_toml_parameters( + base_params, + package_env_config, + SCRIPT_NAME, + wheel_names, + wheel_dependencies, + ) + ) + + if wheel_name not in PYPROJECT_PY_PARAMETERS.keys(): + print(f"Unknown wheel name '{wheel_name}'") sys.exit(1) # Configure 'pyproject.toml' - output_file = os.path.join(args.output_dir, "pyproject.toml") - configure(template, PYPROJECT_PY_PARAMETERS[args.wheel_name], output_file) - - # Configure or remove 'itk/__init__.py' - # init_py = os.path.join(args.output_dir, "itk", "__init__.py") - # if args.wheel_name in ["itk", "itk-core"]: - # with open(init_py, 'w') as file_: - # file_.write("# Stub required for package\n") - # else: - # if os.path.exists(init_py): - # os.remove(init_py) + output_file = os.path.join(output_dir, "pyproject.toml") + print(f"Generating: {output_file}") + template = os.path.join(SCRIPT_DIR, "pyproject.toml.in") + configure(template, PYPROJECT_PY_PARAMETERS[wheel_name], output_file) + + +def write_itkVersion_py(filename: str | Path, itk_package_version: str): + """Write an ``itkVersion.py`` file reporting the ITK package version. + + Parameters + ---------- + filename : str or Path + Output file path. + itk_package_version : str + PEP 440 version string to embed. + """ + itk_version_python_code = f""" +VERSION: str = '{itk_package_version}' + +def get_versions() -> str: + \"\"\"Returns versions for the ITK Python package. + + from itkVersion import get_versions + + # Returns the ITK repository version + get_versions()['version'] + + # Returns the package version. Since GitHub Releases do not support the '+' + # character in file names, this does not contain the local version + # identifier in nightly builds, i.e. + # + # '6.0.1.dev20251126' + # + # instead of + # + # '6.0.1.dev20251126+139.g922f2d9' + get_versions()['package-version'] + \"\"\" + + versions = {{}} + versions['version'] = VERSION + versions['package-version'] = VERSION.split('+')[0] + return versions +""" + with open(filename, "w") as wfid: + wfid.write(itk_version_python_code) if __name__ == "__main__": diff --git a/scripts/update_python_version.py b/scripts/update_python_version.py deleted file mode 100755 index f69207d3..00000000 --- a/scripts/update_python_version.py +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/env python - -"""Update the ITKPythonPackage version based off the ITK Git nightly-master -branch.""" - -import argparse -import sys -import os -import subprocess -from datetime import datetime -from packaging.version import Version - -argparser = argparse.ArgumentParser(description=__doc__) -argparser.add_argument("itkSourceDir") - -args = argparser.parse_args() -itkSourceDir = args.itkSourceDir -if not os.path.exists(os.path.join(itkSourceDir, ".git")): - print("itkSourceDir does not appear to be a git repository!") - sys.exit(1) - -itkPythonPackageDir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - - -os.chdir(itkSourceDir) -# "Wed Feb 8 15:21:09 2017"\n -commitDate = subprocess.check_output( - ["git", "show", "-s", "--date=local", '--format="%cd"'] -) -# Wed Feb 8 15:21:09 2017 -commitDate = commitDate.strip()[1:-1] -# Wed Feb 08 15:21:09 2017 -commitDate = commitDate.split(" ") -commitDate[2] = "{:02d}".format(int(commitDate[2])) -commitDate = " ".join(commitDate) -# 2017-02-08 -commitDateDashes = datetime.strptime(commitDate, "%a %b %d %H:%M:%S %Y").strftime( - "%Y-%m-%d" -) -# 20170208 -commitDate = commitDateDashes.replace("-", "") - -# v4.11.0-139-g922f2d9 -# -revision = subprocess.check_output(["git", "describe", "--tags", "--long"]) -revision.strip() -# 4.11.0-139-g922f2d9 -revision = revision[1:] -version, numberOfCommits, gHash = revision.split("-") -version = version.strip() -numberOfCommits = numberOfCommits.strip() -gHash = gHash.strip() - -pythonRevision = version -if int(numberOfCommits) > 0: - pythonRevision += ".dev" - pythonRevision += commitDate - pythonRevision += "+" - pythonRevision += numberOfCommits - pythonRevision += "." - pythonRevision += gHash - -os.chdir(itkPythonPackageDir) -itkVersionPath = os.path.join(itkPythonPackageDir, "itkVersion.py") - -Version(VERSION) # Raise InvalidVersion exception if not PEP 440 compliant - -if not os.path.exists(itkVersionPath): - print("Expected file " + itkVersionPath + " not found!") - sys.exit(1) -with open(itkVersionPath, "r") as fp: - lines = fp.readlines() -with open(itkVersionPath, "w") as fp: - for line in lines: - if line.startswith("VERSION = "): - fp.write("VERSION = '") - fp.write(pythonRevision) - fp.write("'\n") - else: - fp.write(line) - - -with open("CMakeLists.txt", "r") as fp: - lines = fp.readlines() -with open("CMakeLists.txt", "w") as fp: - for line in lines: - if line.startswith(" # ITK nightly-master"): - fp.write(" # ITK nightly-master ") - fp.write(commitDateDashes) - fp.write("\n") - elif line.startswith(" set(ITK_GIT_TAG"): - fp.write(' set(ITK_GIT_TAG "') - fp.write(gHash[1:]) - fp.write('")\n') - else: - fp.write(line) diff --git a/scripts/update_python_version.sh b/scripts/update_python_version.sh deleted file mode 100755 index 9773056e..00000000 --- a/scripts/update_python_version.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env bash - -# This script is use to update the version of ITK used by ITKPythonPackage. It -# is run nightly by a system with push permissions to the -# -# git@github.com:InsightSoftwareConsortium/ITKPythonPackage.git -# -# repository. - -set -x -e - -workdir=/tmp/ - -cd $workdir - -if test ! -d ITKNightlyMaster; then - git clone --branch nightly-master \ - https://github.com/InsightSoftwareConsortium/ITK.git ITKNightlyMaster -fi -pushd ITKNightlyMaster/ -git checkout nightly-master -git fetch -git reset --hard origin/nightly-master -ITK_SHA=$(git rev-parse --short HEAD) -popd - -if test ! -d ITKPythonPackage; then - git clone --branch master \ - git@github.com:InsightSoftwareConsortium/ITKPythonPackage.git ITKPythonPackage -fi -pushd ITKPythonPackage/ -git checkout master -git fetch -git reset --hard origin/master -git config user.name 'Kitware Robot' -git config user.email 'kwrobot@kitware.com' -ITKPythonPackage_SHA=$(git rev-parse --short HEAD) -./scripts/update_python_version.py ../ITKNightlyMaster -git add -- CMakeLists.txt itkVersion.py -git commit -m "ITK nightly version update - -This commit updates: - (1) SHA used in CMakeLists.txt to checkout ITK sources - (InsightSoftwareConsortium/ITK@${ITK_SHA}) - (2) VERSION variable set in itkVersion.py - -It was automatically generated by the script ``update_python_version.sh`` [1] - -[1] https://github.com/InsightSoftwareConsortium/ITKPythonPackage/blob/${ITKPythonPackage_SHA}/scripts/update_python_version.py" -git push origin master diff --git a/scripts/wheel_builder_utils.py b/scripts/wheel_builder_utils.py new file mode 100644 index 00000000..1c40dc77 --- /dev/null +++ b/scripts/wheel_builder_utils.py @@ -0,0 +1,752 @@ +"""This module provides convenient function facilitating scripting. + +These functions have been copied from scikit-build project. +See https://github.com/scikit-build/scikit-build +""" + +import filecmp +import os +import re +import shutil +import subprocess +import sys + +# from contextlib import contextmanager +from functools import wraps +from os import chdir as os_chdir +from os import environ +from pathlib import Path + +# @contextmanager +# def push_env(**kwargs): +# """This context manager allow to set/unset environment variables.""" +# saved_env = dict(os_environ) +# for var, value in kwargs.items(): +# if value is not None: +# os_environ[var] = value +# elif var in os_environ: +# del os_environ[var] +# yield +# os_environ.clear() +# for saved_var, saved_value in saved_env.items(): +# os_environ[saved_var] = saved_value + + +class ContextDecorator: + """A base class or mixin that enables context managers to work as + decorators.""" + + def __init__(self, **kwargs): + self.__dict__.update(kwargs) + + def __enter__(self): + # Note: Returning self means that in "with ... as x", x will be self + return self + + def __exit__(self, typ, val, traceback): + pass + + def __call__(self, func): + @wraps(func) + def inner(*args, **kwds): # pylint:disable=missing-docstring + with self: + return func(*args, **kwds) + + return inner + + +class push_dir(ContextDecorator): + """Context manager to change current directory.""" + + def __init__(self, directory=None, make_directory=False): + """ + :param directory: + Path to set as current working directory. If ``None`` + is passed, current working directory is used instead. + + :param make_directory: + If True, ``directory`` is created. + """ + self.directory = None + self.make_directory = None + self.old_cwd = None + super().__init__(directory=directory, make_directory=make_directory) + + def __enter__(self): + self.old_cwd = Path.cwd() + if self.directory: + if self.make_directory: + Path(self.directory).mkdir(parents=True, exist_ok=True) + os_chdir(self.directory) + return self + + def __exit__(self, typ, val, traceback): + os_chdir(self.old_cwd) + + +def _remove_tree(path: Path) -> None: + """Recursively delete a file or directory using pathlib only. + + Parameters + ---------- + path : Path + File or directory to remove. No error is raised if *path* + does not exist. + """ + if not path.exists(): + return + if path.is_file() or path.is_symlink(): + try: + path.unlink() + except OSError: + pass + return + for child in path.iterdir(): + _remove_tree(child) + try: + path.rmdir() + except OSError: + pass + + +def read_env_file( + file_path: os.PathLike | str, build_dir_root: os.PathLike | str +) -> dict[str, str]: + """Read a simple .env-style file and return a dict of key/value pairs. + + Supported syntax: + + - Blank lines and lines starting with ``#`` are ignored. + - Optional leading ``export`` prefix is stripped. + - ``KEY=VALUE`` pairs; surrounding single or double quotes are stripped. + - Whitespace around keys and the ``=`` is ignored. + - ``${BUILD_DIR_ROOT}`` in values is replaced with *build_dir_root*. + + This function does not perform variable expansion or modify ``os.environ``. + + Parameters + ---------- + file_path : os.PathLike or str + Path to the ``.env`` file. + build_dir_root : os.PathLike or str + Value substituted for ``${BUILD_DIR_ROOT}`` placeholders in values. + + Returns + ------- + dict[str, str] + Parsed key/value pairs. Returns an empty dict if the file does + not exist or cannot be read. + """ + result: dict[str, str] = {} + path = Path(file_path) + if not path.exists(): + return result + try: + content = path.read_text(encoding="utf-8") + except Exception: + return result + + for raw_line in content.splitlines(): + line = raw_line.strip() + if not line or line.startswith("#"): + continue + if line.startswith("export "): + line = line[len("export ") :].lstrip() + if "=" not in line: + continue + key, value = line.split("=", 1) + key = key.strip() + value = value.strip() + value = value.replace("${BUILD_DIR_ROOT}", str(build_dir_root)) + # Strip surrounding quotes if present + if (len(value) >= 2) and ( + (value[0] == value[-1] == '"') or (value[0] == value[-1] == "'") + ): + value = value[1:-1] + result[key] = value + return result + + +def _which(exe_name: str) -> Path | None: + """Locate an executable on ``PATH`` using pathlib. + + A custom implementation is used because ``shutil.which`` does not + reliably resolve executables on Windows before Python 3.12. + + Parameters + ---------- + exe_name : str + Name (or path fragment) of the executable to find. + + Returns + ------- + Path or None + Absolute path to the first matching executable, or ``None`` if + not found. + """ + # shutil.which only works on windows after python 3.12. + pathext: list[str] = environ.get("PATHEXT", ".EXE;.BAT;.CMD;.exe;.bat;.cmd").split( + ";" + ) + paths: list[str] = environ.get("PATH", "").split(os.pathsep) + exe: Path = Path(exe_name) + candidates: list[Path] = ( + [exe] if exe.suffix else [Path(exe_name + ext) for ext in pathext] + ) + candidates = [exe] + candidates + for p in paths: + if not p: + continue + base = Path(p) + for c in candidates: + fp = base / c + try: + if fp.exists(): + return fp + except OSError: + continue + return None + + +def detect_platform() -> tuple[str, str]: + """Detect the current operating system and CPU architecture. + + Returns + ------- + tuple[str, str] + A ``(os_name, arch)`` pair where *os_name* is one of + ``'linux'``, ``'darwin'``, ``'windows'``, or ``'unknown'``, and + *arch* is a normalized architecture string (e.g. ``'x64'``, + ``'arm64'``, ``'x86_64'``, ``'aarch64'``). + """ + uname = os.uname() if hasattr(os, "uname") else None + sysname = ( + uname.sysname if uname else ("Windows" if os.name == "nt" else sys.platform) + ) + machine = ( + uname.machine + if uname + else (os.environ.get("PROCESSOR_ARCHITECTURE", "").lower()) + ) + os_name = ( + "linux" + if sysname.lower().startswith("linux") + else ( + "darwin" + if sysname.lower().startswith("darwin") or sys.platform == "darwin" + else ("windows" if os.name == "nt" else "unknown") + ) + ) + # Normalize machine + arch = machine + if os_name == "darwin": + if machine in ("x86_64",): + arch = "x86_64" + elif machine in ("arm64", "aarch64"): + arch = "arm64" + elif os_name == "linux": + if machine in ("x86_64",): + arch = "x64" + elif machine in ("i686", "i386"): + arch = "x86" + elif machine in ("aarch64",): + arch = "aarch64" + return os_name, arch + + +def which_required(name: str) -> str: + path = shutil.which(name) + if not path: + raise RuntimeError( + f"MISSING: {name} not found in PATH; aborting until required executables can be found" + ) + return path + + +def run_commandLine_subprocess( + cmd: list[str | Path], + cwd: Path | None = None, + env: dict = None, + check: bool = False, +) -> subprocess.CompletedProcess: + """Run a command via ``subprocess.run`` with logging. + + Parameters + ---------- + cmd : list[str or Path] + Command and arguments to execute. + cwd : Path, optional + Working directory for the subprocess. + env : dict, optional + Environment variables for the subprocess. + check : bool, optional + If True, raise ``RuntimeError`` on non-zero exit codes. + + Returns + ------- + subprocess.CompletedProcess + Completed process information including stdout, stderr, and + return code. + + Raises + ------ + RuntimeError + If *check* is True and the command exits with a non-zero code. + """ + cmd = [str(x) for x in cmd] + print(f"Running >>>>>: {' '.join(cmd)} ; # in cwd={cwd} with check={check}\n") + completion_info = subprocess.run( + cmd, + cwd=str(cwd) if cwd else None, + capture_output=True, + text=True, + env=env if env else None, + ) + if completion_info.returncode != 0 and check: + error_msg = "!~" * 40 + if env: + error_msg += "ENVIRONMENT: =================" + for k, v in env.items(): + error_msg += f"\n{k}={v}" + error_msg += "==============================" + if completion_info.stdout: + error_msg += f"\nStdout:\n {completion_info.stdout}" + if completion_info.stderr: + error_msg += f"\nStderr:\n {completion_info.stderr}" + error_msg += f"Command failed with exit code {completion_info.returncode}: {' '.join(cmd)}" + print(error_msg) + raise RuntimeError(error_msg) + + return completion_info + + +def git_describe_to_pep440(desc: str) -> str: + """ + Convert `git describe --tags --long --dirty --always` output + + # v6.0b03-3-g1a2b3c4 + # │ | │ └── abbreviated commit hash + # │ | └────── commits since tag + # | └────────── pre-release type and number + # └────────────── nearest tag + to a PEP 440–compatible version string. + + [N!]N(.N)*[{a|b|rc}N][.postN][.devN]+ + 111122222233333333333444444445555555666666666666 + 1 Epoch segment: N! + 2 Release segment: N(.N)* + 3 Pre-release segment: {a|b|rc}N + 4 Post-release segment: .postN + 5 Development release segment: .devN + 6 local info not used in version ordering. I.e. ignored by package resolution rules + """ + desc = desc.strip() + semver_format = "0.0.0" + + m = re.match( + r"^(v)*(?P\d+)(?P\.\d+)(?P\.\d+)*(?Pa|b|rc|alpha|beta)*0*(?P\d*)-*(?P\d*)-*g*(?P[0-9a-fA-F]+)*(?P.dirty)*$", + desc, + ) + if m: + groupdict = m.groupdict() + + semver_format = ( + f"{groupdict.get('majorver','')}" + f"{groupdict.get('minor','')}" + ) + patch = groupdict.get("patch", None) + if patch: + semver_format += f"{patch}" + else: + semver_format += ".0" + + prereleasemapping = { + "alpha": "a", + "a": "a", + "beta": "b", + "b": "b", + "rc": "rc", + "": "", + } + prerelease_name = prereleasemapping.get(groupdict.get("pretype", ""), None) + prerelnum = groupdict.get("prerelnum", None) + if prerelease_name and prerelnum and len(prerelease_name) > 0: + semver_format += f"{prerelease_name}{prerelnum}" + posttagcount = groupdict.get("posttagcount", None) + dirty = groupdict.get("dirty", None) + if ( + len(posttagcount) > 0 + and int(posttagcount) == 0 + and (dirty is None or len(dirty) == 0) + ): + # If exactly on a tag, then do not add post, or sha + return semver_format + else: + if posttagcount and int(posttagcount) > 0: + semver_format += f".post{posttagcount}" + sha = groupdict.get("sha", None) + if sha: + semver_format += f"+g{sha.lower()}" + if dirty: + semver_format += ".dirty" + return semver_format + + +# def debug(msg: str, do_print=False) -> None: +# """Print *msg* only when *do_print* is True.""" +# if do_print: +# print(msg) +# +# +# def parse_kv_overrides(pairs: list[str]) -> dict[str, str]: +# """Parse a list of ``KEY=VALUE`` strings into a dict. +# +# A value of ``"UNSET"`` is stored as ``None`` so callers can remove +# the key from a target mapping. +# +# Parameters +# ---------- +# pairs : list[str] +# Strings of the form ``KEY=VALUE``. +# +# Returns +# ------- +# dict[str, str] +# Parsed overrides. +# +# Raises +# ------ +# SystemExit +# If an entry is not a valid ``KEY=VALUE`` pair or the key name +# is invalid. +# """ +# result: dict[str, str] = {} +# for kv in pairs: +# if "=" not in kv: +# raise SystemExit(f"ERROR: Trailing argument '{kv}' is not KEY=VALUE") +# key, value = kv.split("=", 1) +# if not key or not re.match(r"^[A-Za-z_][A-Za-z0-9_]*$", key): +# raise SystemExit(f"ERROR: Invalid variable name '{key}' in '{kv}'") +# if value == "UNSET": +# # Explicitly remove if present later +# result[key] = None # type: ignore +# else: +# result[key] = value +# return result + + +# def get_git_id( +# repo_dir: Path, pixi_exec_path, env, backup_version: str = "v0.0.0" +# ) -> str | None: +# """Return a human-readable Git identifier for *repo_dir*. +# +# Tries, in order: exact tag, branch name, short commit hash. +# Falls back to *backup_version* when none of these succeed. +# +# Parameters +# ---------- +# repo_dir : Path +# Root of the Git repository. +# pixi_exec_path : Path or str +# Path to the pixi executable (unused but kept for API compat). +# env : dict +# Environment variables passed to Git subprocesses. +# backup_version : str, optional +# Fallback identifier returned when Git queries fail. +# +# Returns +# ------- +# str or None +# A tag, branch name, short hash, or *backup_version*. +# """ +# # 1. exact tag +# try: +# run_result = run_commandLine_subprocess( +# ["git", "describe", "--tags", "--exact-match"], +# cwd=repo_dir, +# env=env, +# check=False, +# ) +# +# if run_result.returncode == 0: +# return run_result.stdout.strip() +# except subprocess.CalledProcessError: +# pass +# # 2. branch +# try: +# run_result = run_commandLine_subprocess( +# ["git", "rev-parse", "--abbrev-ref", "HEAD"], +# cwd=repo_dir, +# env=env, +# ) +# branch = run_result.stdout.strip() +# if run_result.returncode == 0 and branch != "HEAD": +# return branch +# except subprocess.CalledProcessError: +# pass +# # 3. short hash +# try: +# run_result = run_commandLine_subprocess( +# ["git", "rev-parse", "--short", "HEAD"], +# cwd=repo_dir, +# env=env, +# ) +# short_version = run_result.stdout.strip() +# if run_result.returncode == 0 and short_version != "HEAD": +# return short_version +# except subprocess.CalledProcessError: +# pass +# +# # 4. punt and give dummy backup_version identifier +# if not (repo_dir / ".git").is_dir(): +# if (repo_dir / ".git").is_file(): +# print( +# f"WARNING: {str(repo_dir)} is a secondary git worktree, and may not resolve from within dockcross build" +# ) +# return backup_version +# print(f"ERROR: {repo_dir} is not a primary git repository") +# return backup_version + + +def compute_itk_package_version( + itk_dir: Path, itk_git_tag: str, pixi_exec_path, env +) -> str: + """Compute a PEP 440 version string for the ITK package. + + Fetches tags, checks out *itk_git_tag*, and runs + ``git describe --tags --long --dirty --always`` to produce a version + via `git_describe_to_pep440`. + + Parameters + ---------- + itk_dir : Path + Path to the ITK source repository. + itk_git_tag : str + Git tag, branch, or commit to check out before describing. + pixi_exec_path : Path or str + Path to the pixi executable (unused but kept for API compat). + env : dict + Environment variables passed to Git subprocesses. + + Returns + ------- + str + PEP 440-compliant version string. + """ + # Try to compute from git describe + try: + run_commandLine_subprocess( + ["git", "fetch", "--tags"], + cwd=itk_dir, + env=env, + ) + try: + run_commandLine_subprocess( + ["git", "checkout", itk_git_tag], + cwd=itk_dir, + env=env, + ) + except Exception as e: + print( + f"WARNING: Failed to checkout {itk_git_tag}, reverting to 'main': {e}" + ) + itk_git_tag = "main" + run_commandLine_subprocess( + ["git", "checkout", itk_git_tag], + cwd=itk_dir, + env=env, + ) + desc = run_commandLine_subprocess( + [ + "git", + "describe", + "--tags", + "--long", + "--dirty", + "--always", + ], + cwd=itk_dir, + env=env, + ).stdout.strip() + version = git_describe_to_pep440(desc) + except subprocess.CalledProcessError: + version = itk_git_tag.lstrip("v") + + return version + + +def default_manylinux( + manylinux_version: str, os_name: str, arch: str, env: dict[str, str] +) -> tuple[str, str, str]: + """Resolve default manylinux container image details. + + Parameters + ---------- + manylinux_version : str + Manylinux specification (e.g. ``'_2_28'``, ``'_2_34'``). + os_name : str + Operating system name (only ``'linux'`` triggers resolution). + arch : str + Target architecture (``'x64'``, ``'aarch64'``). + env : dict[str, str] + Environment variables that may override image defaults + (``IMAGE_TAG``, ``CONTAINER_SOURCE``, ``MANYLINUX_IMAGE_NAME``). + + Returns + ------- + tuple[str, str, str] + ``(image_tag, image_name, container_source)``. + + Raises + ------ + RuntimeError + If *manylinux_version* or *arch* is unrecognized. + """ + image_tag = env.get("IMAGE_TAG", "") + container_source = env.get("CONTAINER_SOURCE", "") + image_name = env.get("MANYLINUX_IMAGE_NAME", "") + + if os_name == "linux": + if arch == "x64" and manylinux_version == "_2_34": + image_tag = image_tag or "latest" + elif arch == "x64" and manylinux_version == "_2_28": + image_tag = image_tag or "20250913-6ea98ba" + elif arch == "aarch64" and manylinux_version == "_2_28": + image_tag = image_tag or "2025.08.12-1" + elif manylinux_version == "": + image_tag = "" + else: + raise RuntimeError( + f"FAILURE: Unknown manylinux version {manylinux_version}" + ) + + if arch == "x64": + image_name = ( + image_name or f"manylinux{manylinux_version}-{arch}:{image_tag}" + ) + container_source = container_source or f"docker.io/dockcross/{image_name}" + elif arch == "aarch64": + image_name = ( + image_name or f"manylinux{manylinux_version}_{arch}:{image_tag}" + ) + container_source = container_source or f"quay.io/pypa/{image_name}" + else: + raise RuntimeError(f"Unknown target architecture {arch}") + + return image_tag, image_name, container_source + + +def resolve_oci_exe(env: dict[str, str]) -> str: + """Find an OCI container runtime (docker, podman, or nerdctl). + + Checks ``OCI_EXE`` in *env* first, then probes ``PATH`` for known + runtimes. Defaults to ``'docker'`` if nothing is found. + + Parameters + ---------- + env : dict[str, str] + Environment variables; ``OCI_EXE`` is checked first. + + Returns + ------- + str + Name or path of the OCI runtime executable. + """ + if env.get("OCI_EXE"): + return env["OCI_EXE"] + for cand in ("docker", "podman", "nerdctl"): + if _which(cand): # NOTE shutil.which ALWAYS RETURNS NONE ON WINDOWS before 3.12 + return cand + # Default to docker name if nothing found + return "docker" + + +# def cmake_compiler_defaults(build_dir: Path) -> tuple[str | None, str | None]: +# info = build_dir / "cmake_system_information" +# if not info.exists(): +# try: +# out = run_commandLine_subprocess(["cmake", "--system-information"]).stdout +# info.write_text(out, encoding="utf-8") +# except Exception as e: +# print(f"WARNING: Failed to generate cmake_system_information: {e}") +# return None, None +# text = info.read_text(encoding="utf-8", errors="ignore") +# cc = None +# cxx = None +# for line in text.splitlines(): +# if "CMAKE_C_COMPILER == " in line: +# parts = re.split(r"\s+", line.strip()) +# if len(parts) >= 4: +# cc = parts[3] +# if "CMAKE_CXX_COMPILER == " in line: +# parts = re.split(r"\s+", line.strip()) +# if len(parts) >= 4: +# cxx = parts[3] +# return cc, cxx + + +def give_relative_path(bin_exec: Path, build_dir_root: Path) -> str: + bin_exec = Path(bin_exec).resolve() + build_dir_root = Path(build_dir_root).resolve() + if bin_exec.is_relative_to(build_dir_root): + return "${BUILD_DIR_ROOT}" + os.sep + str(bin_exec.relative_to(build_dir_root)) + return str(bin_exec) + + +def safe_copy_if_different(src: Path, dst: Path) -> None: + """Copy file only if destination is missing or contents differ. + + This avoids unnecessary overwrites and timestamp churn when files are identical. + """ + src = Path(src) + dst = Path(dst) + if not dst.exists(): + dst.parent.mkdir(parents=True, exist_ok=True) + shutil.copyfile(src, dst) + return + try: + same = filecmp.cmp(src, dst, shallow=False) + except Exception as e: + # On any comparison failure, fall back to copying to be safe + same = False + print(f"WARNING: Failed to compare {src} to {dst}: {e}") + if not same: + shutil.copyfile(src, dst) + + +def get_default_platform_build(default_python_version: str = "py311") -> str: + """Return a default ``-`` build identifier. + + Inspects the ``PIXI_ENVIRONMENT_NAME`` environment variable first; + falls back to ``sys.platform`` detection. + + Parameters + ---------- + default_python_version : str, optional + Python version suffix used when not running inside pixi + (default ``'py311'``). + + Returns + ------- + str + A string like ``'manylinux_2_28-py311'`` or ``'macosx-py311'``. + """ + from_pixi = os.environ.get("PIXI_ENVIRONMENT_NAME", None) + if from_pixi and "-" in from_pixi: + manylinux_pixi_to_pattern_renaming: dict[str, str] = { + "manylinux228": "manylinux_2_28", + "manylinux234": "manylinux_2_34", + } + platform_prefix: str = from_pixi.split("-")[0] + python_version: str = from_pixi.split("-")[1] + platform_prefix = manylinux_pixi_to_pattern_renaming.get( + platform_prefix, platform_prefix + ) + return f"{platform_prefix}-{python_version}" + else: + if sys.platform == "darwin": + return f"macosx-{default_python_version}" + elif sys.platform.startswith("linux"): + return f"linux-{default_python_version}" + elif sys.platform == "win32": + return f"windows-{default_python_version}" + return f"unknown-{default_python_version}" diff --git a/scripts/windows-build-tarball.ps1 b/scripts/windows-build-tarball.ps1 deleted file mode 100644 index dab4f09f..00000000 --- a/scripts/windows-build-tarball.ps1 +++ /dev/null @@ -1,8 +0,0 @@ -# This script creates a tarball of the ITK Python package build tree. It is -# downloaded by the external module build scripts and used to build their -# Python package on GitHub CI services. - -cd C:\P\ -Remove-Item IPP\dist\* -C:\7-Zip\7z.exe a -t7z -r 'C:\P\ITKPythonBuilds-windows.zip' -w 'C:\P\IPP' -# C:\7-Zip\7z.exe a -t7z -mx=9 -mfb=273 -ms -md=31 -myx=9 -mtm=- -mmt -mmtf -md=1536m -mmf=bt3 -mmc=10000 -mpb=0 -mlc=0 -r 'C:\P\ITKPythonBuilds-windows.zip' -w 'C:\P\IPP' diff --git a/scripts/windows-download-cache-and-build-module-wheels.ps1 b/scripts/windows-download-cache-and-build-module-wheels.ps1 index 0d7b8fe2..512ca641 100644 --- a/scripts/windows-download-cache-and-build-module-wheels.ps1 +++ b/scripts/windows-download-cache-and-build-module-wheels.ps1 @@ -1,134 +1,271 @@ ######################################################################## -# Pull build dependencies and build an ITK external module. +# Pull build dependencies and build an ITK external module on Windows. # -# This script must be run in an x64 Developer Powershell. +# This script must be run in an x64 Developer PowerShell. # See https://learn.microsoft.com/en-us/visualstudio/ide/reference/command-prompt-powershell?view=vs-2022#developer-powershell # # ----------------------------------------------------------------------- -# Positional parameters: -# - 0th parameter or -python_version_minor option: Python minor version. +# Positional parameters / named options: +# +# -python_version_minor Python minor version (required). # For instance, for Python 3.11: -# > windows-download-cache-and-build-module-wheels.ps1 11 -# or equivalently: # > windows-download-cache-and-build-module-wheels.ps1 -python_version_minor 11 +# or positionally: +# > windows-download-cache-and-build-module-wheels.ps1 11 # -# - 1st parameter or -setup_options: pyproject.toml options. -# For instance, for Python 3.11, excluding nvcuda.dll during packaging: -# > windows-download-cache-and-build-module-wheels.ps1 11 "--exclude-libs nvcuda.dll" -# or equivalently: -# > windows-download-cache-and-build-module-wheels.ps1 -python_version_minor 11 -setup_options "--exclude-libs nvcuda.dll" -# -# - 2nd parameter or -cmake_options: CMake options passed to pyproject.tom for project configuration. -# For instance, for Python 3.11, excluding nvcuda.dll during packaging -# and setting RTK_USE_CUDA ON during configuration: -# > windows-download-cache-and-build-module-wheels.ps1 11 "--exclude-libs nvcuda.dll" "-DRTK_USE_CUDA:BOOL=ON" -# or equivalently: -# > windows-download-cache-and-build-module-wheels.ps1 -python_version_minor 11 -setup_options "--exclude-libs nvcuda.dll" -cmake-options "-DRTK_USE_CUDA:BOOL=ON" +# -setup_options pyproject.toml options forwarded to the build script. +# For instance, to exclude a library during packaging: +# > ... -setup_options "--exclude-libs nvcuda.dll" # +# -cmake_options CMake options passed to pyproject.toml for project configuration. +# For instance: +# > ... -cmake_options "-DRTK_USE_CUDA:BOOL=ON" # # ----------------------------------------------------------------------- # Environment variables used in this script: # -# `$env:ITK_PACKAGE_VERSION`: Tag for ITKPythonBuilds build archive to use +# `$env:ITK_PACKAGE_VERSION` +# Tag for the ITKPythonBuilds archive to download/use. Required. # -# `$env:ITKPYTHONPACKAGE_TAG`: Tag for ITKPythonPackage build scripts to use. -# If ITKPYTHONPACKAGE_TAG is empty then the default scripts distributed -# with the ITKPythonBuilds archive will be used. +# `$env:ITKPYTHONPACKAGE_TAG` +# Tag for ITKPythonPackage build scripts to use. +# If empty, the scripts bundled in the archive will be used. # -# `$env:ITKPYTHONPACKAGE_ORG`: Github organization or user to use for ITKPythonPackage -# build script source. Default is InsightSoftwareConsortium. +# `$env:ITKPYTHONPACKAGE_ORG` +# GitHub organization/user for ITKPythonPackage. Default: InsightSoftwareConsortium. # Ignored if ITKPYTHONPACKAGE_TAG is empty. # -# `$env:ITK_MODULE_PREQ`: Delimited list of ITK module dependencies to build before building the target module. -# Format is `/@:/@:...`. -# For instance, `export ITK_MODULE_PREQ=InsightSoftwareConsortium/ITKMeshToPolyData@v0.10.0` +# `$env:ITK_MODULE_PREQ` +# Colon-delimited list of ITK module dependencies. +# Format: `/@:/@:...` +# Example: `InsightSoftwareConsortium/ITKMeshToPolyData@v0.10.0` +# Passed directly to build_wheels.py via --itk-module-deps. +# +# `$env:MODULE_SRC_DIRECTORY` +# Path to the ITK external module source. Defaults to the directory +# containing this script. # ######################################################################## param ( [int]$python_version_minor, - [string]$setup_options, - [string]$cmake_options + [string]$setup_options = "", + [string]$cmake_options = "" ) -$pythonArch = "64" -$pythonVersion = "3.$python_version_minor" -echo "Pulling Python $pythonVersion-x$pythonArch" -iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/scikit-build/scikit-ci-addons/master/windows/install-python.ps1')) +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" -if (-not $env:ITK_PACKAGE_VERSION) { $env:ITK_PACKAGE_VERSION = 'v5.4.0' } -echo "Fetching build archive $env:ITK_PACKAGE_VERSION" -if (Test-Path C:\P) { - Remove-Item -Recurse -Force C:\P +# Validate required inputs +if (-not $python_version_minor) { + Write-Error "ERROR: -python_version_minor is required. Example: -python_version_minor 11" + exit 1 } -if (-not (Test-Path ITKPythonBuilds-windows.zip)) { - Invoke-WebRequest -Uri "https://github.com/InsightSoftwareConsortium/ITKPythonBuilds/releases/download/$env:ITK_PACKAGE_VERSION/ITKPythonBuilds-windows.zip" -OutFile "ITKPythonBuilds-windows.zip" +if (-not $env:ITK_PACKAGE_VERSION) { + Write-Error "ERROR: `$env:ITK_PACKAGE_VERSION must be set before running this script." + exit 1 } -7z x ITKPythonBuilds-windows.zip -oC:\P -aoa -r -# Optional: Update ITKPythonPackage build scripts -if ($env:ITKPYTHONPACKAGE_TAG) { - if(-not $env:ITKPYTHONPACKAGE_ORG) { - $env:ITKPYTHONPACKAGE_ORG="InsightSoftwareConsortium" +# Resolve configuration +$MODULE_SRC_DIRECTORY = if ($env:MODULE_SRC_DIRECTORY) { + $env:MODULE_SRC_DIRECTORY +} else { + $PSScriptRoot +} +echo "MODULE_SRC_DIRECTORY: $MODULE_SRC_DIRECTORY" + +$ITK_PACKAGE_VERSION = $env:ITK_PACKAGE_VERSION +# For backwards compatibility when the ITK_GIT_TAG was required to match the ITK_PACKAGE_VERSION +$ITK_GIT_TAG = if ($env:ITK_GIT_TAG) { $env:ITK_GIT_TAG } else { $ITK_PACKAGE_VERSION } +$ITKPYTHONPACKAGE_ORG = if ($env:ITKPYTHONPACKAGE_ORG) { $env:ITKPYTHONPACKAGE_ORG } else { "InsightSoftwareConsortium" } +$ITKPYTHONPACKAGE_TAG = if ($env:ITKPYTHONPACKAGE_TAG) { $env:ITKPYTHONPACKAGE_TAG } else { "" } + +$DASHBOARD_BUILD_DIRECTORY = "C:\BDR" +$platformEnv = "windows-py3$python_version_minor" + +echo "Python version : 3.$python_version_minor" +echo "ITK_PACKAGE_VERSION: $ITK_PACKAGE_VERSION" +echo "ITK_GIT_TAG : $ITK_GIT_TAG" +echo "Platform env : $platformEnv" + +# --------------------------------------------------------------------------- +# Check for conda/pixi-provided ITK (libitk-wrapping package). +# When available, skip the archive download entirely. +# --------------------------------------------------------------------------- +$condaItkDir = $null +foreach ($prefixVar in @("CONDA_PREFIX", "PIXI_ENVIRONMENT_DIR")) { + $prefix = [System.Environment]::GetEnvironmentVariable($prefixVar) + if ($prefix -and (Test-Path "$prefix\lib\cmake")) { + foreach ($candidate in (Get-ChildItem "$prefix\lib\cmake" -Directory -Filter "ITK-*" -ErrorAction SilentlyContinue)) { + if (Test-Path "$($candidate.FullName)\ITKConfig.cmake") { + $condaItkDir = $candidate.FullName + echo "Detected conda-installed ITK at $condaItkDir (via `$$prefixVar)" + break + } + } + if ($condaItkDir) { break } } +} - echo "Updating build scripts to $env:ITKPYTHONPACKAGE_ORG/ITKPythonPackage@$env:ITKPYTHONPACKAGE_TAG" +if ($condaItkDir) { + echo "Using conda-installed ITK; skipping archive download." + # Use local ITKPythonPackage scripts + $ippDir = $PSScriptRoot | Split-Path +} else { - pushd C:\P - git clone "https://github.com/$env:ITKPYTHONPACKAGE_ORG/ITKPythonPackage.git" "IPP-tmp" - pushd "IPP-tmp" - git checkout "$env:ITKPYTHONPACKAGE_TAG" - git status - popd +# Install pixi and required global tools +# NOTE: Python and Doxygen are provided by the pixi environment; no need to +# install them separately here. +$env:PIXI_HOME = "$DASHBOARD_BUILD_DIRECTORY\.pixi" +if (-not (Test-Path "$env:PIXI_HOME\bin\pixi.exe")) { + echo "Installing pixi..." + Invoke-WebRequest -Uri "https://pixi.sh/install.ps1" -OutFile "install-pixi.ps1" + powershell -ExecutionPolicy Bypass -File "install-pixi.ps1" +} +$env:Path = "$env:PIXI_HOME\bin;$env:Path" - Remove-Item -Recurse -Force IPP/scripts/ - Copy-Item -Recurse IPP-tmp/scripts IPP/ - Copy-Item IPP-tmp/requirements-dev.txt IPP/ - Remove-Item -Recurse -Force IPP-tmp/ - popd +# Install global packages via pixi for use in this script +# Note: Using conda-forge packages that are available on Windows +echo "Installing global tools via pixi..." +$globalPackages = @( + "git", # Required for cloning ITKPythonPackage repo + "aria2" # Fast download utility (cross-platform) +) + +foreach ($pkg in $globalPackages) { + echo " Installing $pkg..." + try { + & pixi global install $pkg + if ($LASTEXITCODE -ne 0) { + echo " Warning: Failed to install $pkg (exit code: $LASTEXITCODE)" + } + } catch { + echo " Warning: Failed to install $pkg - $($_.Exception.Message)" + } +} + +# Refresh PATH to include pixi global binaries +$env:Path = "$env:PIXI_HOME\bin;$env:Path" + +# --------------------------------------------------------------------------- +# Download ITKPythonBuilds archive +# --------------------------------------------------------------------------- +$zipName = "ITKPythonBuilds-windows.zip" +$zipDownloadUrl = "https://github.com/InsightSoftwareConsortium/ITKPythonBuilds/releases/download/$ITK_PACKAGE_VERSION/$zipName" +$localZipName = "ITKPythonBuilds-windows.zip" + +if (Test-Path $localZipName) { + echo "Found cached archive: $localZipName -- skipping download." +} else { + echo "Downloading $zipDownloadUrl ..." + + # Try first (faster, resumable), fall back to Invoke-WebRequest + $aria2Path = Get-Command aria2c -ErrorAction SilentlyContinue + if ($aria2Path) { + echo " Using aria2c for download..." + & aria2c -c --file-allocation=none -s 10 -x 10 -o $localZipName $zipDownloadUrl + } else { + echo " Using Invoke-WebRequest for download..." + Invoke-WebRequest -Uri $zipDownloadUrl -OutFile $localZipName + } } -# Get other build dependencies -if (-not (Test-Path doxygen-1.16.1.windows.bin.zip)) { - Invoke-WebRequest -Uri "https://github.com/doxygen/doxygen/releases/download/Release_1_16_1/doxygen-1.16.1.windows.x64.bin.zip" -OutFile "doxygen-1.16.1.windows.bin.zip" +# Unpack archive +# Expected layout after extraction under $DASHBOARD_BUILD_DIRECTORY: +# \ITK ITK source tree +# \build\ pre-built ITK artifacts +# \IPP ITKPythonPackage scripts + +echo "Extracting archive to $DASHBOARD_BUILD_DIRECTORY ..." +# Use 7-Zip to extract (matches the format it was created in) +$sevenZipPath = "C:\Program Files\7-Zip\7z.exe" +if (-not (Test-Path $sevenZipPath)) { + Write-Error "7-Zip not found at $sevenZipPath. Please install 7-Zip." + exit 1 } -7z x doxygen-1.16.1.windows.bin.zip -oC:\P\doxygen -aoa -r -if (-not (Test-Path grep-win.zip)) { - Invoke-WebRequest -Uri "https://data.kitware.com/api/v1/file/5bbf87ba8d777f06b91f27d6/download/grep-win.zip" -OutFile "grep-win.zip" + +& $sevenZipPath x $localZipName -o"$DASHBOARD_BUILD_DIRECTORY" -y +if ($LASTEXITCODE -ne 0) { + Write-Error "Failed to extract archive (exit code: $LASTEXITCODE)" + exit 1 } -7z x grep-win.zip -oC:\P\grep -aoa -r -$env:Path += ";C:\P\grep" +# Optional: overlay ITKPythonPackage build scripts from a specific tag +cd "$DASHBOARD_BUILD_DIRECTORY\IPP" +$env:PATH += ";C:\Program Files\Git\bin" +if ($ITKPYTHONPACKAGE_TAG) { + echo "Updating build scripts to $ITKPYTHONPACKAGE_ORG/ITKPythonPackage@$ITKPYTHONPACKAGE_TAG" + + $ippTmpDir = "$DASHBOARD_BUILD_DIRECTORY\IPP-tmp" + $ippCloneUrl = "https://github.com/$ITKPYTHONPACKAGE_ORG/ITKPythonPackage.git" + + if (-not (Test-Path "$ippTmpDir\.git")) { + echo " Cloning repository..." + & git clone $ippCloneUrl $ippTmpDir -# Build ITK module dependencies, if any -$build_command = "& `"C:\Python$pythonVersion-x$pythonArch\python.exe`" `"C:\P\IPP\scripts\windows_build_module_wheels.py`" --no-cleanup --py-envs `"3$python_version_minor-x64`"" -if ("$setup_options".length -gt 0) { - $build_command = "$build_command $setup_options" + # Check if clone succeeded + if ($LASTEXITCODE -ne 0 -or -not (Test-Path $ippTmpDir)) { + Write-Error "Failed to clone ITKPythonPackage repository" + exit 1 + } + } + + pushd $ippTmpDir + echo " Checking out $ITKPYTHONPACKAGE_TAG..." + & git checkout $ITKPYTHONPACKAGE_TAG + & git reset "origin/$ITKPYTHONPACKAGE_TAG" --hard + & git status + popd + + echo " Copying updated scripts..." + Copy-Item -Recurse -Force "$ippTmpDir\*" "$DASHBOARD_BUILD_DIRECTORY\IPP\" + Remove-Item -Recurse -Force $ippTmpDir } -if("$cmake_options".length -gt 0) { - $build_command = "$build_command -- $cmake_options" + +} # end else (tarball download path) + +# Build the module wheel +# Assemble paths used by build_wheels.py +if (-not $ippDir) { + $ippDir = "$DASHBOARD_BUILD_DIRECTORY\IPP" } -echo $build_command +$buildScript = "$ippDir\scripts\build_wheels.py" +# build_wheels.py expects the cached ITK build at \build\ITK-windows-py3XX-... +# Since the zip extracts directly into BDR (i.e. BDR\build\ITK-windows-py311-...), BDR is the root. +$buildDirRoot = $DASHBOARD_BUILD_DIRECTORY +$itkSourceDir = "$DASHBOARD_BUILD_DIRECTORY\ITK" +$moduleDepsDir = "$DASHBOARD_BUILD_DIRECTORY\MDEPS" + +# Instead of building a string and using iex, build an argument array +$buildArgs = @( + "run", "-e", $platformEnv, + "python", $buildScript, + "--platform-env", $platformEnv, + "--module-source-dir", $MODULE_SRC_DIRECTORY, + "--module-dependencies-root-dir", $moduleDepsDir +) -echo "ITK_MODULE_PREQ: $env:ITK_MODULE_PREQ $ITK_MODULE_PREQ" if ($env:ITK_MODULE_PREQ) { - $MODULES_LIST = $env:ITK_MODULE_PREQ.split(":") - foreach($MODULE_INFO in $MODULES_LIST) { - $MODULE_ORG = $MODULE_INFO.split("/")[0] - $MODULE_NAME = $MODULE_INFO.split("@")[0].split("/")[1] - $MODULE_TAG = $MODULE_INFO.split("@")[1] - - $MODULE_UPSTREAM = "https://github.com/$MODULE_ORG/$MODULE_NAME.git" - echo "Cloning from $MODULE_UPSTREAM" - git clone $MODULE_UPSTREAM - - pushd $MODULE_NAME - git checkout $MODULE_TAG - echo "Building $MODULE_NAME" - iex $build_command - popd - - Copy-Item $MODULE_NAME/include/* include/ - } + $buildArgs += @("--itk-module-deps", $env:ITK_MODULE_PREQ) +} + +$buildArgs += @( + "--no-build-itk-tarball-cache", + "--build-dir-root", $buildDirRoot, + "--itk-git-tag", $ITK_GIT_TAG, + "--itk-source-dir", $itkSourceDir, + "--itk-package-version", $ITK_PACKAGE_VERSION, + "--no-use-ccache", + "--skip-itk-build", + "--skip-itk-wheel-build" +) + +if ($setup_options.Length -gt 0) { + $buildArgs += $setup_options.Split(" ") +} + +if ($cmake_options.Length -gt 0) { + $buildArgs += @("--") + $buildArgs += $cmake_options.Split(" ") } -# Run build scripts -iex $build_command +echo "Building target module..." +& pixi @buildArgs diff --git a/scripts/windows_build_module_wheels.py b/scripts/windows_build_module_wheels.py deleted file mode 100755 index 0a8f54f3..00000000 --- a/scripts/windows_build_module_wheels.py +++ /dev/null @@ -1,251 +0,0 @@ -#!/usr/bin/env python - -# See usage with .\scripts\windows_build_module_wheels.py --help - -from subprocess import check_call -import os -import glob -import sys -import argparse -import shutil -from pathlib import Path - -SCRIPT_DIR = os.path.dirname(__file__) -ROOT_DIR = os.path.abspath(os.getcwd()) - -print("SCRIPT_DIR: %s" % SCRIPT_DIR) -print("ROOT_DIR: %s" % ROOT_DIR) - -sys.path.insert(0, os.path.join(SCRIPT_DIR, "internal")) - -from wheel_builder_utils import push_dir, push_env -from windows_build_common import DEFAULT_PY_ENVS, venv_paths - - -def install_and_import(package): - """ - Install package with pip and import in current script. - """ - import importlib - - try: - importlib.import_module(package) - except ImportError: - import pip - - pip.main(["install", package]) - finally: - globals()[package] = importlib.import_module(package) - - -def build_wheels(py_envs=DEFAULT_PY_ENVS, cleanup=True, cmake_options=[]): - for py_env in py_envs: - ( - python_executable, - python_include_dir, - python_library, - python_sabi_library, - pip, - ninja_executable, - path, - ) = venv_paths(py_env) - - with push_env(PATH="%s%s%s" % (path, os.pathsep, os.environ["PATH"])): - # Install dependencies - check_call([python_executable, "-m", "pip", "install", "pip", "--upgrade"]) - requirements_file = os.path.join(ROOT_DIR, "requirements-dev.txt") - if os.path.exists(requirements_file): - check_call([pip, "install", "--upgrade", "-r", requirements_file]) - check_call([pip, "install", "cmake"]) - check_call([pip, "install", "scikit-build-core", "--upgrade"]) - - check_call([pip, "install", "ninja", "--upgrade"]) - check_call([pip, "install", "delvewheel"]) - - source_path = ROOT_DIR - itk_build_path = os.path.abspath( - "%s/ITK-win_%s" % (os.path.join(SCRIPT_DIR, ".."), py_env) - ) - print("ITKDIR: %s" % itk_build_path) - - minor_version = py_env.split("-")[0][1:] - if int(minor_version) >= 11: - # Stable ABI - wheel_py_api = "cp3%s" % minor_version - else: - wheel_py_api = "" - # Generate wheel - check_call( - [ - python_executable, - "-m", - "build", - "--verbose", - "--wheel", - "--outdir", - "dist", - "--no-isolation", - "--skip-dependency-check", - "--config-setting=wheel.py-api=%s" % wheel_py_api, - "--config-setting=cmake.define.SKBUILD:BOOL=ON", - "--config-setting=cmake.define.PY_SITE_PACKAGES_PATH:PATH=.", - "--config-setting=cmake.args=-G Ninja", - "--config-setting=cmake.define.CMAKE_BUILD_TYPE:STRING=Release", - "--config-setting=cmake.define.CMAKE_MAKE_PROGRAM:FILEPATH=%s" - % ninja_executable, - "--config-setting=cmake.define.ITK_DIR:PATH=%s" - % itk_build_path, - "--config-setting=cmake.define.WRAP_ITK_INSTALL_COMPONENT_IDENTIFIER:STRING=PythonWheel", - "--config-setting=cmake.define.SWIG_EXECUTABLE:FILEPATH=%s/Wrapping/Generators/SwigInterface/swig/bin/swig.exe" - % itk_build_path, - "--config-setting=cmake.define.BUILD_TESTING:BOOL=OFF", - "--config-setting=cmake.define.CMAKE_INSTALL_LIBDIR:STRING=lib", - "--config-setting=cmake.define.Python3_EXECUTABLE:FILEPATH=%s" - % python_executable, - "--config-setting=cmake.define.Python3_INCLUDE_DIR:PATH=%s" - % python_include_dir, - "--config-setting=cmake.define.Python3_INCLUDE_DIRS:PATH=%s" - % python_include_dir, - "--config-setting=cmake.define.Python3_LIBRARY:FILEPATH=%s" - % python_library, - "--config-setting=cmake.define.Python3_SABI_LIBRARY:FILEPATH=%s" - % python_sabi_library, - ] - + [ - o.replace("-D", "--config-setting=cmake.define.") - for o in cmake_options - ] - + [ - ".", - ] - ) - - -def rename_wheel_init(py_env, filepath, add_module_name=True): - """ - Rename module __init__ (if add_module_name is True) or __init_module__ (if - add_module_name is False) file in wheel. This is required to prevent - modules to override ITK's __init__ file on install or to prevent delvewheel - to override __init_module__ file. If the module ships its own __init__ - file, it is automatically renamed to __init_{module_name}__ by this - function. The renamed __init__ file will be executed by ITK's __init__ file - when loading ITK. - """ - ( - python_executable, - python_include_dir, - python_library, - python_sabi_library, - pip, - ninja_executable, - path, - ) = venv_paths(py_env) - - # Get module info - install_and_import("pkginfo") - w = pkginfo.Wheel(filepath) - module_name = w.name.split("itk-")[-1] - module_version = w.version - - dist_dir = os.path.dirname(filepath) - wheel_dir = os.path.join( - dist_dir, "itk_" + module_name.replace("-", "_") + "-" + module_version - ) - init_dir = os.path.join(wheel_dir, "itk") - init_file = os.path.join(init_dir, "__init__.py") - init_file_module = os.path.join( - init_dir, "__init_" + module_name.split("-")[0] + "__.py" - ) - - # Unpack wheel and rename __init__ file if it exists. - check_call([python_executable, "-m", "wheel", "unpack", filepath, "-d", dist_dir]) - if add_module_name and os.path.isfile(init_file): - shutil.move(init_file, init_file_module) - if not add_module_name and os.path.isfile(init_file_module): - shutil.move(init_file_module, init_file) - - # Pack wheel and clean wheel folder - check_call([python_executable, "-m", "wheel", "pack", wheel_dir, "-d", dist_dir]) - shutil.rmtree(wheel_dir) - - -def fixup_wheel(py_envs, filepath, lib_paths: str = "", exclude_libs: str = ""): - lib_paths = ";".join(["C:/P/IPP/oneTBB-prefix/bin", lib_paths.strip()]).strip(";") - print(f"Library paths for fixup: {lib_paths}") - - py_env = py_envs[0] - - # Make sure the module __init_module__.py file has the expected name for - # delvewheel, i.e., __init__.py. - rename_wheel_init(py_env, filepath, False) - - delve_wheel = os.path.join( - "C:/P/IPP", "venv-" + py_env, "Scripts", "delvewheel.exe" - ) - check_call( - [ - delve_wheel, - "repair", - "--no-mangle-all", - "--add-path", - lib_paths, - "--no-dll", - exclude_libs, - "--ignore-in-wheel", - "-w", - os.path.join(ROOT_DIR, "dist"), - filepath, - ] - ) - - # The delve_wheel patch loading shared libraries is added to the module - # __init__ file. Rename this file here to prevent conflicts on installation. - # The renamed __init__ file will be executed when loading ITK. - rename_wheel_init(py_env, filepath) - - -def fixup_wheels(py_envs, lib_paths: str = "", exclude_libs: str = ""): - # shared library fix-up - for wheel in glob.glob(os.path.join(ROOT_DIR, "dist", "*.whl")): - fixup_wheel(py_envs, wheel, lib_paths, exclude_libs) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser( - description="Driver script to build ITK Python module wheels." - ) - parser.add_argument( - "--py-envs", - nargs="+", - default=DEFAULT_PY_ENVS, - help='Target Python environment versions, e.g. "310-x64".', - ) - parser.add_argument( - "--no-cleanup", - dest="cleanup", - action="store_false", - help="Do not clean up temporary build files.", - ) - parser.add_argument( - "--lib-paths", - nargs=1, - default="", - help="Add semicolon-delimited library directories for delvewheel to include in the module wheel", - ) - parser.add_argument( - "--exclude-libs", - nargs=1, - default="", - help='Add semicolon-delimited library names that must not be included in the module wheel, e.g. "nvcuda.dll"', - ) - parser.add_argument( - "cmake_options", - nargs="*", - help="Extra options to pass to CMake, e.g. -DBUILD_SHARED_LIBS:BOOL=OFF", - ) - args = parser.parse_args() - - build_wheels( - cleanup=args.cleanup, py_envs=args.py_envs, cmake_options=args.cmake_options - ) - fixup_wheels(args.py_envs, ";".join(args.lib_paths), ";".join(args.exclude_libs)) diff --git a/scripts/windows_build_python_instance.py b/scripts/windows_build_python_instance.py new file mode 100644 index 00000000..0f966db1 --- /dev/null +++ b/scripts/windows_build_python_instance.py @@ -0,0 +1,256 @@ +import re +from pathlib import Path + +from build_python_instance_base import BuildPythonInstanceBase + + +class WindowsBuildPythonInstance(BuildPythonInstanceBase): + """Windows-specific wheel builder. + + Handles Windows path conventions, pixi-based Python environment + discovery, and ``delvewheel`` for wheel repair. + """ + + def prepare_build_env(self) -> None: + """Set up the Windows build environment, TBB paths, and venv info.""" + # ############################################# + # ### Setup build tools + self.package_env_config["USE_TBB"] = "ON" + self.package_env_config["TBB_DIR"] = str( + self.build_dir_root / "build" / "oneTBB-prefix" / "lib" / "cmake" / "TBB" + ) + # The interpreter is provided; ensure basic tools are available + self.venv_paths() + self.update_venv_itk_build_configurations() + + target_arch = self.package_env_config["ARCH"] + itk_binary_build_name: Path = ( + self.build_dir_root + / "build" + / f"ITK-{self.platform_env}-{self.get_pixi_environment_name()}_{target_arch}" + ) + + self.cmake_itk_source_build_configurations.set( + "ITK_BINARY_DIR:PATH", str(itk_binary_build_name) + ) + + # Keep values consistent with prior quoting behavior + # self.cmake_compiler_configurations.set("CMAKE_CXX_FLAGS:STRING", "-O3 -DNDEBUG") + # self.cmake_compiler_configurations.set("CMAKE_C_FLAGS:STRING", "-O3 -DNDEBUG") + + def post_build_fixup(self) -> None: + """Repair wheels with ``delvewheel``, including oneTBB library paths.""" + # append the oneTBB-prefix\\bin directory for fixing wheels built with local oneTBB + search_lib_paths = ( + [s for s in str(self.windows_extra_lib_paths[0]).rstrip(";") if s] + if self.windows_extra_lib_paths + else [] + ) + search_lib_paths.append(str(self.build_dir_root / "oneTBB-prefix" / "bin")) + search_lib_paths_str: str = ";".join(map(str, search_lib_paths)) + self.fixup_wheels(search_lib_paths_str) + + def fixup_wheel( + self, filepath, lib_paths: str = "", remote_module_wheel: bool = False + ) -> None: + """Repair a wheel using ``delvewheel`` with the given library paths. + + Parameters + ---------- + filepath : str + Path to the ``.whl`` file to repair. + lib_paths : str, optional + Semicolon-delimited directories to add to ``delvewheel --add-path``. + remote_module_wheel : bool, optional + Unused on Windows (kept for interface compatibility). + """ + # Windows fixup_wheel + lib_paths = lib_paths.strip() + lib_paths = lib_paths + ";" if lib_paths else "" + print(f"Library paths for fixup: {lib_paths}") + + delve_wheel = "delvewheel.exe" + cmd = [ + str(delve_wheel), + "repair", + "--no-mangle-all", + "--add-path", + lib_paths.strip(";"), + "--ignore-in-wheel", + "-w", + str(self.build_dir_root / "dist"), + str(filepath), + ] + self.echo_check_call(cmd) + + def build_tarball(self): + """Create an archive of the ITK Python package build tree (Windows). + + Mirrors scripts/windows-build-tarball.ps1 behavior: + - Remove contents of IPP/dist + - Use 7-Zip, when present, to archive the full IPP tree into + ITKPythonBuilds-windows.zip at the parent directory of IPP (e.g., C:\P) + - Fallback to Python's zip archive creation if 7-Zip is unavailable + """ + + # out_zip = self.build_dir_root / "build" / "ITKPythonBuilds-windows.zip" + out_zip = self.build_dir_root / "ITKPythonBuilds-windows.zip" + + # 1) Clean IPP/dist contents (do not remove the directory itself) + dist_dir = self.build_dir_root / "dist" + if dist_dir.exists(): + for p in dist_dir.glob("*"): + try: + if p.is_dir(): + # shutil.rmtree alternative without importing here + for sub in p.rglob("*"): + # best-effort clean + try: + if sub.is_file() or sub.is_symlink(): + sub.unlink(missing_ok=True) + except Exception: + pass + try: + p.rmdir() + except Exception: + pass + else: + p.unlink(missing_ok=True) + except Exception: + # best-effort cleanup; ignore errors to continue packaging + pass + + # 2) Try to use 7-Zip if available + seven_zip_candidates = [ + Path(r"C:\\7-Zip\\7z.exe"), + Path(r"C:\\Program Files\\7-Zip\\7z.exe"), + Path(r"C:\\Program Files (x86)\\7-Zip\\7z.exe"), + ] + + seven_zip = None + for cand in seven_zip_candidates: + if cand.exists(): + seven_zip = cand + break + + if seven_zip is None: + # Try PATH lookup using where/which behavior from shutil + import shutil as _shutil + + found = _shutil.which("7z.exe") or _shutil.which("7z") + if found: + seven_zip = Path(found) + + if seven_zip is not None: + cmd = [ + str(seven_zip), + "a", + "-t7z", + "-r", + str(out_zip), + str(self.build_dir_root / "ITK"), + str(self.build_dir_root / "build"), + str(self.ipp_dir), + "-xr!*.o", + "-xr!*.obj", # Windows equivalent of .o + "-xr!wheelbuilds", # Do not include the wheelbuild support directory + "-xr!__pycache__", # Do not include __pycache__ + "-xr!install_manifest_*.txt", # Do not include install manifest files + "-xr!.git", # Exclude git directory + "-xr!.idea", # Exclude IDE directory + "-xr!.pixi", # Exclude pixi environment + "-xr!castxml_inputs", + "-xr!Wrapping\Modules", + "-xr!*.pdb", # Exclude debug symbols + ] + return_status: int = self.echo_check_call(cmd) + if return_status == 0: + return + + # 3) Fallback: create a .zip using Python's shutil + # This will create a zip archive named ITKPythonBuilds-windows.zip + import shutil as _shutil + + if out_zip.exists(): + try: + out_zip.unlink() + except Exception: + pass + # make_archive requires base name without extension + base_name = str(out_zip.with_suffix("").with_suffix("")) + # shutil.make_archive will append .zip + _shutil.make_archive( + base_name, + "zip", + root_dir=str(self.build_dir_root), + base_dir=str(self.build_dir_root.name), + ) + + def venv_paths(self) -> None: + """Populate ``venv_info_dict`` from the pixi-managed Python environment on Windows.""" + + def get_python_version(platform_env: str) -> None | tuple[int, int]: + pattern = re.compile(r"py3(?P\d+)") + m = pattern.search(platform_env) + if not m: + return None + return 3, int(m.group("minor")) + + # Get the python executable path + python_exe = Path(self.package_env_config["PYTHON_EXECUTABLE"]) + + # For the pixi environment structure: + # python.exe is at: /python.exe + # Headers are at: /include/ + # Libraries are at: /libs/ + env_root = python_exe.parent # C:/BDR/IPP/.pixi/envs/windows-py311 + + venv_bin_path = env_root # Where python.exe is + venv_base_dir = env_root + + # Python development files are directly under env root + python_include_dir = env_root / "include" + + python_major, python_minor = get_python_version(self.platform_env) + # Version-specific library (e.g., python311.lib) - required for + # CMake's FindPython3 to extract version info for Development.Module + xy_lib_ver = f"{python_major}{python_minor}" + python_library = env_root / "libs" / f"python{xy_lib_ver}.lib" + + # Stable ABI library (python3.lib) - for Development.SABIModule + if python_minor >= 11: + python_sabi_library = env_root / "libs" / f"python{python_major}.lib" + else: + python_sabi_library = python_library + + self.venv_info_dict = { + "python_include_dir": python_include_dir, # .../windows-py311/include + "python_library": python_library, # .../windows-py311/libs/python311.lib + "python_sabi_library": python_sabi_library, # .../windows-py311/libs/python3.lib + "venv_bin_path": venv_bin_path, # .../windows-py311 + "venv_base_dir": venv_base_dir, # .../windows-py311 + "python_root_dir": env_root, # .../windows-py311 + } + + def discover_python_venvs( + self, platform_os_name: str, platform_architecture: str + ) -> list[str]: + """Return default Windows Python environment names. + + Parameters + ---------- + platform_os_name : str + Operating system identifier (unused, kept for interface). + platform_architecture : str + Architecture suffix appended to each environment name. + + Returns + ------- + list[str] + Environment names like ``['39-x64', '310-x64', '311-x64']``. + """ + default_platform_envs = [ + f"310-{platform_architecture}", + f"311-{platform_architecture}", + ] + return default_platform_envs diff --git a/scripts/windows_build_wheels.py b/scripts/windows_build_wheels.py deleted file mode 100644 index 4c1404bd..00000000 --- a/scripts/windows_build_wheels.py +++ /dev/null @@ -1,411 +0,0 @@ -#!/usr/bin/env python - -import argparse -import glob -import json -import os -import shutil -import sys -import tempfile -import textwrap - -from subprocess import check_call, check_output - - -SCRIPT_DIR = os.path.dirname(__file__) -ROOT_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, "..")) -ITK_SOURCE = os.path.join(ROOT_DIR, "ITK-source") - -print("SCRIPT_DIR: %s" % SCRIPT_DIR) -print("ROOT_DIR: %s" % ROOT_DIR) -print("ITK_SOURCE: %s" % ITK_SOURCE) - -sys.path.insert(0, os.path.join(SCRIPT_DIR, "internal")) -from wheel_builder_utils import push_dir, push_env -from windows_build_common import DEFAULT_PY_ENVS, venv_paths - - -def pip_install(python_dir, package, upgrade=True): - pip = os.path.join(python_dir, "Scripts", "pip.exe") - print("Installing %s using %s" % (package, pip)) - args = [pip, "install"] - if upgrade: - args.append("--upgrade") - args.append(package) - check_call(args) - - -def prepare_build_env(python_version): - python_dir = "C:/Python%s" % python_version - if not os.path.exists(python_dir): - raise FileNotFoundError( - "Aborting. python_dir [%s] does not exist." % python_dir - ) - - venv = os.path.join(python_dir, "Scripts", "virtualenv.exe") - venv_dir = os.path.join(ROOT_DIR, "venv-%s" % python_version) - print("Creating python virtual environment: %s" % venv_dir) - if not os.path.exists(venv_dir): - check_call([venv, venv_dir]) - pip_install(venv_dir, "scikit-build-core") - pip_install(venv_dir, "ninja") - pip_install(venv_dir, "delvewheel") - - -def build_wrapped_itk( - ninja_executable, - build_type, - source_path, - build_path, - python_executable, - python_include_dir, - python_library, - python_sabi_library, -): - tbb_dir = os.path.join(ROOT_DIR, "oneTBB-prefix", "lib", "cmake", "TBB") - - # Build ITK python - with push_dir(directory=build_path, make_directory=True): - check_call( - [ - "cmake", - "-DCMAKE_MAKE_PROGRAM:FILEPATH=%s" % ninja_executable, - "-DCMAKE_BUILD_TYPE:STRING=%s" % build_type, - "-DITK_SOURCE_DIR:PATH=%s" % source_path, - "-DITK_BINARY_DIR:PATH=%s" % build_path, - "-DBUILD_TESTING:BOOL=OFF", - "-DSKBUILD:BOOL=ON", - "-DPython3_EXECUTABLE:FILEPATH=%s" % python_executable, - "-DITK_WRAP_unsigned_short:BOOL=ON", - "-DITK_WRAP_double:BOOL=ON", - "-DITK_WRAP_complex_double:BOOL=ON", - "-DITK_WRAP_IMAGE_DIMS:STRING=2;3;4", - "-DPython3_INCLUDE_DIR:PATH=%s" % python_include_dir, - "-DPython3_INCLUDE_DIRS:PATH=%s" % python_include_dir, - "-DPython3_LIBRARY:FILEPATH=%s" % python_library, - "-DPython3_SABI_LIBRARY:FILEPATH=%s" % python_sabi_library, - "-DWRAP_ITK_INSTALL_COMPONENT_IDENTIFIER:STRING=PythonWheel", - "-DWRAP_ITK_INSTALL_COMPONENT_PER_MODULE:BOOL=ON", - "-DPY_SITE_PACKAGES_PATH:PATH=.", - "-DITK_LEGACY_SILENT:BOOL=ON", - "-DITK_WRAP_PYTHON:BOOL=ON", - "-DITK_WRAP_DOC:BOOL=ON", - "-DDOXYGEN_EXECUTABLE:FILEPATH=C:/P/doxygen/doxygen.exe", - "-DModule_ITKTBB:BOOL=ON", - "-DTBB_DIR:PATH=%s" % tbb_dir, - "-G", - "Ninja", - source_path, - ] - ) - check_call([ninja_executable]) - - -def build_wheel( - python_version, - build_type="Release", - single_wheel=False, - cleanup=True, - wheel_names=None, - cmake_options=[], -): - ( - python_executable, - python_include_dir, - python_library, - python_sabi_library, - pip, - ninja_executable, - path, - ) = venv_paths(python_version) - - with push_env(PATH="%s%s%s" % (path, os.pathsep, os.environ["PATH"])): - # Install dependencies - check_call( - [ - pip, - "install", - "--upgrade", - "-r", - os.path.join(ROOT_DIR, "requirements-dev.txt"), - ] - ) - - source_path = "%s/ITK" % ITK_SOURCE - build_path = "%s/ITK-win_%s" % (ROOT_DIR, python_version) - pyproject_configure = os.path.join(SCRIPT_DIR, "pyproject_configure.py") - - # Clean up previous invocations - if cleanup and os.path.exists(build_path): - shutil.rmtree(build_path) - - if single_wheel: - print("#") - print("# Build single ITK wheel") - print("#") - - # Configure pyproject.toml - check_call([python_executable, pyproject_configure, "itk"]) - - # Generate wheel - check_call( - [ - python_executable, - "-m", - "build", - "--verbose", - "--wheel", - "--outdir", - "dist", - "--no-isolation", - "--skip-dependency-check", - "--config-setting=cmake.build-type=%s" % build_type, - "--config-setting=cmake.define.ITK_SOURCE_DIR:PATH=%s" - % source_path, - "--config-setting=cmake.define.ITK_BINARY_DIR:PATH=%s" % build_path, - "--config-setting=cmake.define.Python3_EXECUTABLE:FILEPATH=%s" - % python_executable, - "--config-setting=cmake.define.Python3_INCLUDE_DIR:PATH=%s" - % python_include_dir, - "--config-setting=cmake.define.Python3_INCLUDE_DIRS:PATH=%s" - % python_include_dir, - "--config-setting=cmake.define.Python3_LIBRARY:FILEPATH=%s" - % python_library, - "--config-setting=cmake.define.Python3_SABI_LIBRARY:FILEPATH=%s" - % python_sabi_library, - "--config-setting=cmake.define.DOXYGEN_EXECUTABLE:FILEPATH=C:/P/doxygen/doxygen.exe", - ] - + [ - o.replace("-D", "--config-setting=cmake.define.") - for o in cmake_options - ] - + [ - ".", - ] - ) - - else: - print("#") - print("# Build multiple ITK wheels") - print("#") - - build_wrapped_itk( - ninja_executable, - build_type, - source_path, - build_path, - python_executable, - python_include_dir, - python_library, - python_sabi_library, - ) - - # Build wheels - if wheel_names is None: - with open(os.path.join(SCRIPT_DIR, "WHEEL_NAMES.txt"), "r") as content: - wheel_names = [ - wheel_name.strip() for wheel_name in content.readlines() - ] - - for wheel_name in wheel_names: - # Configure pyproject.toml - check_call([python_executable, pyproject_configure, wheel_name]) - - # Generate wheel - check_call( - [ - python_executable, - "-m", - "build", - "--verbose", - "--wheel", - "--outdir", - "dist", - "--no-isolation", - "--skip-dependency-check", - "--config-setting=cmake.build-type=%s" % build_type, - "--config-setting=cmake.define.ITK_SOURCE_DIR:PATH=%s" - % source_path, - "--config-setting=cmake.define.ITK_BINARY_DIR:PATH=%s" - % build_path, - "--config-setting=cmake.define.ITKPythonPackage_ITK_BINARY_REUSE:BOOL=ON", - "--config-setting=cmake.define.ITKPythonPackage_WHEEL_NAME:STRING=%s" - % wheel_name, - "--config-setting=cmake.define.Python3_EXECUTABLE:FILEPATH=%s" - % python_executable, - "--config-setting=cmake.define.Python3_INCLUDE_DIR:PATH=%s" - % python_include_dir, - "--config-setting=cmake.define.Python3_INCLUDE_DIRS:PATH=%s" - % python_include_dir, - "--config-setting=cmake.define.Python3_LIBRARY:FILEPATH=%s" - % python_library, - "--config-setting=cmake.define.Python3_SABI_LIBRARY:FILEPATH=%s" - % python_sabi_library, - ] - + [ - o.replace("-D", "--config-setting=cmake.define.") - for o in cmake_options - ] - + [ - ".", - ] - ) - - # Remove unnecessary files for building against ITK - if cleanup: - for root, _, file_list in os.walk(build_path): - for filename in file_list: - extension = os.path.splitext(filename)[1] - if extension in [".cpp", ".xml", ".obj", ".o"]: - os.remove(os.path.join(root, filename)) - shutil.rmtree(os.path.join(build_path, "Wrapping", "Generators", "CastXML")) - - -def fixup_wheel(py_envs, filepath, lib_paths: str = ""): - lib_paths = lib_paths.strip() if lib_paths.isspace() else lib_paths.strip() + ";" - lib_paths += "C:/P/IPP/oneTBB-prefix/bin" - print(f"Library paths for fixup: {lib_paths}") - - py_env = py_envs[0] - - delve_wheel = os.path.join(ROOT_DIR, "venv-" + py_env, "Scripts", "delvewheel.exe") - check_call( - [ - delve_wheel, - "repair", - "--no-mangle-all", - "--add-path", - lib_paths, - "--ignore-in-wheel", - "-w", - os.path.join(ROOT_DIR, "dist"), - filepath, - ] - ) - - -def fixup_wheels(single_wheel, py_envs, lib_paths: str = ""): - # TBB library fix-up - tbb_wheel = "itk_core" - if single_wheel: - tbb_wheel = "itk" - for wheel in glob.glob(os.path.join(ROOT_DIR, "dist", tbb_wheel + "*.whl")): - fixup_wheel(py_envs, wheel, lib_paths) - - -def test_wheels(python_env): - ( - python_executable, - python_include_dir, - python_library, - python_sabi_library, - pip, - ninja_executable, - path, - ) = venv_paths(python_env) - check_call([pip, "install", "numpy"]) - check_call([pip, "install", "itk", "--no-cache-dir", "--no-index", "-f", "dist"]) - print("Wheel successfully installed.") - check_call([python_executable, os.path.join(ROOT_DIR, "docs/code/test.py")]) - print("Documentation tests passed.") - - -def build_wheels( - py_envs=DEFAULT_PY_ENVS, - single_wheel=False, - cleanup=False, - wheel_names=None, - cmake_options=[], -): - for py_env in py_envs: - prepare_build_env(py_env) - - build_type = "Release" - - with push_dir(directory=ITK_SOURCE, make_directory=True): - cmake_executable = "cmake.exe" - tools_venv = os.path.join(ROOT_DIR, "venv-" + py_envs[0]) - ninja_executable = shutil.which("ninja.exe") - if ninja_executable is None: - pip_install(tools_venv, "ninja") - ninja_executable = os.path.join(tools_venv, "Scripts", "ninja.exe") - - # Build standalone project and populate archive cache - check_call( - [ - cmake_executable, - "-DCMAKE_BUILD_TYPE:STRING=%s" % build_type, - "-DITKPythonPackage_BUILD_PYTHON:PATH=0", - "-G", - "Ninja", - "-DCMAKE_MAKE_PROGRAM:FILEPATH=%s" % ninja_executable, - ROOT_DIR, - ] - ) - - check_call([ninja_executable]) - - # Compile wheels re-using standalone project and archive cache - for py_env in py_envs: - tools_venv = os.path.join(ROOT_DIR, "venv-" + py_env) - ninja_executable = shutil.which("ninja.exe") - if ninja_executable is None: - pip_install(tools_venv, "ninja") - build_wheel( - py_env, - build_type, - single_wheel=single_wheel, - cleanup=cleanup, - wheel_names=wheel_names, - cmake_options=cmake_options, - ) - - -def main(wheel_names=None): - parser = argparse.ArgumentParser( - description="Driver script to build ITK Python wheels." - ) - parser.add_argument( - "--single-wheel", - action="store_true", - help="Build a single wheel as opposed to one wheel per ITK module group.", - ) - parser.add_argument( - "--py-envs", - nargs="+", - default=DEFAULT_PY_ENVS, - help='Target Python environment versions, e.g. "310-x64".', - ) - parser.add_argument( - "--no-cleanup", - dest="cleanup", - action="store_false", - help="Do not clean up temporary build files.", - ) - parser.add_argument( - "--lib-paths", - nargs=1, - default="", - help="Add semicolon-delimited library directories for delvewheel to include in the module wheel", - ) - parser.add_argument( - "cmake_options", - nargs="*", - help="Extra options to pass to CMake, e.g. -DBUILD_SHARED_LIBS:BOOL=OFF", - ) - args = parser.parse_args() - - build_wheels( - single_wheel=args.single_wheel, - cleanup=args.cleanup, - py_envs=args.py_envs, - wheel_names=wheel_names, - cmake_options=args.cmake_options, - ) - fixup_wheels(args.single_wheel, args.py_envs, ";".join(args.lib_paths)) - for py_env in args.py_envs: - test_wheels(py_env) - - -if __name__ == "__main__": - main()