fix(installer): install hash-pinned dependencies and build tools (#856)

* fix(installer): install hash-pinned dependencies and build tools

* fix(installer): add cairo-devel for the pinned pycairo build

* fix(installer): reject missing or empty bootstrap exports

* fix(installer): preserve remote behavior for older tags

---------

Co-authored-by: Jatin K Malik <jatinkrmalik@gmail.com>
This commit is contained in:
Sergey Silaev
2026-09-23 00:09:48 -07:00
committed by GitHub
co-authored by Jatin K Malik
parent 4df612dd7a
commit acd90fdd05
12 changed files with 1183 additions and 170 deletions
+4 -1
View File
@@ -108,7 +108,7 @@ Website: `web/AGENTS.md`, `web/PRODUCT.md`, `web/DESIGN.md`. Do not duplicate si
## Dependencies (uv)
`uv.lock` is authoritative. `just lock` regenerates it, the hash-pinned `requirements/*.txt` exports, and `packaging/flatpak/python3-dependencies.yaml`. The AppImage build installs from `runtime`/`vad` plus `appimage.txt`; `install.sh` still resolves at install time (phase 2 of #701). **Do not edit `requirements/*.txt` by hand**, nor the url/sha256 pairs in `packaging/flatpak/python3-dependencies.yaml`. Change `pyproject.toml` (or `requirements/whisper.in` for the Whisper engine, `requirements/appimage*.in` for the AppImage), run `just lock`, and commit the lock plus the exports with the manifest change.
`uv.lock` is authoritative. `just lock` regenerates it, the hash-pinned `requirements/*.txt` exports, and `packaging/flatpak/python3-dependencies.yaml`. The AppImage build installs from `runtime`/`vad` plus `appimage.txt`; `install.sh` consumes the runtime and selected extras with `--require-hashes --no-deps --no-build-isolation`, then installs the project with `--no-deps --no-build-isolation`. **Do not edit `requirements/*.txt` by hand**, nor the url/sha256 pairs in `packaging/flatpak/python3-dependencies.yaml`. Change `pyproject.toml` (or `requirements/whisper.in` for the Whisper engine, `requirements/appimage*.in` for the AppImage), run `just lock`, and commit the lock plus the exports with the manifest change.
| Constraint | Rule |
|---|---|
@@ -116,6 +116,9 @@ Website: `web/AGENTS.md`, `web/PRODUCT.md`, `web/DESIGN.md`. Do not duplicate si
| `[vosk]` extra | Wheel-only on PyPI (no sdist). Never part of a source-buildable lock. `install.sh --engine=vosk` installs it |
| Whisper CPU torch | `requirements/whisper.txt` is compiled from `requirements/whisper.in`. Pin `torch`/`torchaudio` together to `+cpu` local versions — PyPI CUDA wheels win resolution regardless of index order, and torchaudio lags torch on the CPU index |
| pywhispercpp | Pinned in `install.sh` as `PYWHISPERCPP_VERSION` (keep in sync with `uv.lock`) |
| Installer build tools | `[dependency-groups].installer-build` exports to `requirements/installer-build.txt`. Bootstrap uses hashed wheels on new and reused venvs; source builds use these tools without build isolation. Its setuptools `<82` cap is for CPU torch only; do not add it to `[build-system]` (Arch). Backend rebuilds select pywhispercpp's complete hash block from `runtime.txt` via `scripts/installer_requirements.py`, with `--no-deps` so they cannot replace the runtime |
| Installer Whisper export | Compiled universally from Python 3.11, constrained by `runtime.txt` and `installer-build.txt` to keep shared pins consistent. Uses `+cpu` pins and best-match index resolution so the CPU index's older copies of shared packages do not downgrade the runtime |
| Remote installer | After cloning, hand off to the tagged `install.sh` with the original arguments and remote venv path. The installer and its exports must come from the same revision, including when the tag predates the pinned installer |
| `[vad]` extra | `onnxruntime` for Silero VAD |
| One export per extra | Every extra in `pyproject.toml` needs a hash-pinned `requirements/<extra>.txt` (underscores become dashes), written by a `uv export` line in `just lock`. `install.sh` installs six of them, so an extra with no export is an install path with nothing pinned, which is how `[parakeet]`, `[faster_whisper]` and `[vosk]` reached users. `tests/test_dependency_exports.py` enumerates the extras and the installer's call sites rather than trusting the recipe to stay complete; `docs` is the one exemption and it carries its reason in `EXPORT_EXEMPT` |
| Exports match the lock | `just export-check` re-runs every `uv export` line in `just lock` and fails if a committed export is behind `uv.lock`. It reads those lines out of the recipe, so an export added there is checked without touching `scripts/check_exports.py`, and it runs under `UV_OFFLINE=1`: `uv export` reads the lock and nothing else. The lint job runs it, because an export named in the recipe and never regenerated is a snapshot, not a pin. `uv pip compile` targets are out of scope by design (they resolve against live indexes) |
+10
View File
@@ -32,6 +32,16 @@ The installer:
- Downloads the default whisper.cpp tiny model (~74MB), verified against pinned checksums
- Sets up desktop integration and launch wrappers
The source installer uses committed, hash-verified Python dependency exports,
including its pip and source-build tools. GTK/PyGObject still comes from your
distribution, and the venv retains access to system packages. A missing export
or unavailable pinned package causes that installation step to fail; the
existing optional-engine and VAD fallbacks still apply.
Remote installs run the installer from the selected release tag. Older tags
therefore retain their original dependency-install behavior; downloading a new
bootstrap script does not change an older release's pins.
### Installer modes
```bash
+94 -85
View File
@@ -6,6 +6,7 @@
# -e: exit on unhandled command failure -u: error on unset variables
# -o pipefail: a pipeline fails if any stage fails
set -Eeuo pipefail
INSTALLER_ARGS=("$@")
# Exit codes (see --help). 1 remains the generic/unclassified failure.
EXIT_OK=0
@@ -487,7 +488,27 @@ resolve_install_tag
# Check if running from within the vocalinux repo or remotely (via curl)
REPO_URL="https://github.com/VocaHQ/vocalinux.git"
INSTALL_DIR=""
CLEANUP_ON_EXIT="no"
CLEANUP_ON_EXIT="${VOCALINUX_REMOTE_INSTALL:-no}"
handoff_to_tagged_installer() {
local tagged_installer="$INSTALL_DIR/install.sh"
local remote_venv="$HOME/.local/share/vocalinux/venv"
if grep -q 'CLEANUP_ON_EXIT="${VOCALINUX_REMOTE_INSTALL:-no}"' "$tagged_installer"; then
export VOCALINUX_REMOTE_INSTALL=yes
export TMPDIR="$(dirname "$VOCALINUX_TMP_DIR")"
rmdir "$VOCALINUX_TMP_DIR"
exec bash "$tagged_installer" "${INSTALLER_ARGS[@]}" "--venv-dir=$remote_venv"
fi
bash "$tagged_installer" "${INSTALLER_ARGS[@]}" "--venv-dir=$remote_venv" || return $?
if [ ! -f "$INSTALL_DIR/activate-vocalinux.sh" ]; then
print_error "The tagged installer did not create activate-vocalinux.sh."
return 1
fi
mkdir -p "$HOME/.local/bin"
mv "$INSTALL_DIR/activate-vocalinux.sh" "$HOME/.local/bin/activate-vocalinux.sh"
}
# Function to check and install git if needed
ensure_git_installed() {
@@ -661,8 +682,10 @@ else
CLEANUP_ON_EXIT="yes"
print_info "Repository cloned to: $INSTALL_DIR"
# When running remotely, install venv to user's home directory
VENV_DIR="$HOME/.local/share/vocalinux/venv"
# Keep the installer and exports on the selected tag. Legacy tags do not
# understand the remote marker, so the handoff relocates their helper.
handoff_to_tagged_installer
exit "$EXIT_OK"
fi
# Change to install directory
@@ -1767,7 +1790,8 @@ install_system_dependencies() {
local APT_PACKAGES_DEBIAN_BASE="python3-pip python3-gi python3-gi-cairo gir1.2-gtk-3.0 gir1.2-ibus-1.0 libcairo2-dev cmake python3-dev build-essential portaudio19-dev python3-venv pkg-config wget curl unzip vulkan-tools libvulkan-dev $VULKAN_SHADER_PKG xclip xsel wl-clipboard $PYWHISPERCPP_BUILD_DEPS"
local APT_PACKAGES_DEBIAN_11_12="$APT_PACKAGES_DEBIAN_BASE libgirepository1.0-dev gir1.2-ayatanaappindicator3-0.1"
local APT_PACKAGES_DEBIAN_13_PLUS="$APT_PACKAGES_DEBIAN_BASE libgirepository-2.0-dev gir1.2-ayatanaappindicator3-0.1"
local DNF_PACKAGES="python3-pip python3-gobject gtk3 ibus-devel gobject-introspection-devel python3-devel portaudio-devel python3-virtualenv pkg-config cmake wget curl unzip vulkan-tools vulkan-loader-devel glslc patchelf xclip xsel wl-clipboard"
# cairo-devel: the pinned pycairo builds from source; Fedora splits its headers/.pc out.
local DNF_PACKAGES="python3-pip python3-gobject gtk3 ibus-devel gobject-introspection-devel python3-devel portaudio-devel cairo-devel python3-virtualenv pkg-config cmake wget curl unzip vulkan-tools vulkan-loader-devel glslc patchelf xclip xsel wl-clipboard"
local PACMAN_PACKAGES="python-pip python-gobject gtk3 ibus gobject-introspection python-cairo portaudio python-virtualenv pkg-config cmake wget curl unzip base-devel vulkan-tools vulkan-headers shaderc patchelf xclip xsel wl-clipboard"
# ibus + typelib-1_0-IBus-1_0, not ibus-devel: the headers are not needed
# (IBus is reached through GI at runtime), and requiring them pulls gtk-doc,
@@ -2625,10 +2649,6 @@ setup_virtual_environment() {
# Activate virtual environment
source "$VENV_DIR/bin/activate" || { print_error "Failed to activate virtual environment"; exit "$EXIT_MISSING_DEPS"; }
# Update pip and setuptools
print_info "Updating pip, setuptools, and wheel..."
pip install --upgrade pip setuptools wheel || { print_error "Failed to update pip, setuptools, and wheel"; exit "$EXIT_NETWORK"; }
print_info "Virtual environment activated successfully."
}
@@ -2644,6 +2664,24 @@ fi
# Set up virtual environment
setup_virtual_environment
# Also run for reused venvs: setup_virtual_environment returns early for those.
# Wheels only here so bootstrapping cannot itself resolve unpinned build deps.
install_pinned_build_tools() {
local reqs_file="$INSTALL_DIR/requirements/installer-build.txt"
if [ ! -s "$reqs_file" ]; then
print_error "Missing or empty pinned requirements: $reqs_file"
return 1
fi
print_info "Installing pinned pip and source-build tools..."
"$VENV_DIR/bin/python" -m pip install --require-hashes --no-deps \
--only-binary=:all: --ignore-installed \
-r "$reqs_file" --log "$VOCALINUX_TMP_DIR/bootstrap.log"
}
install_pinned_build_tools || {
print_error "Failed to install the pinned build tools. Check requirements/installer-build.txt."
exit "$EXIT_NETWORK"
}
# Create activation script for users
# Put it in ~/.local/bin when running remotely, or current dir when running locally
if [[ "$CLEANUP_ON_EXIT" == "yes" ]]; then
@@ -2872,7 +2910,19 @@ install_cpu_pywhispercpp() {
PYWHISPERCPP_CMAKE_ARGS=$(get_pywhispercpp_cmake_args)
CMAKE_ARGS="${CMAKE_ARGS:+$CMAKE_ARGS }$PYWHISPERCPP_CMAKE_ARGS" \
pip install --verbose --force-reinstall --no-cache-dir "pywhispercpp==${PYWHISPERCPP_VERSION}" --log "$PIP_LOG_FILE"
pip_reinstall_pywhispercpp "$PIP_LOG_FILE"
}
pip_reinstall_pywhispercpp() {
local pip_log="$1"
shift
local reqs_file="$VOCALINUX_TMP_DIR/pywhispercpp.txt"
"$VENV_DIR/bin/python" "$INSTALL_DIR/scripts/installer_requirements.py" \
"$INSTALL_DIR/requirements/runtime.txt" "$reqs_file" --package pywhispercpp || return 1
# --no-deps preserves the locked runtime and avoids reinstalling numpy
# while replacing only the backend. Build tools were bootstrapped above.
"$VENV_DIR/bin/python" -m pip install --require-hashes --no-deps --no-build-isolation \
--verbose --force-reinstall --no-cache-dir -r "$reqs_file" --log "$pip_log" "$@"
}
is_pywhispercpp_installed() {
@@ -3028,7 +3078,7 @@ install_whispercpp_with_gpu_support() {
print_info "Installing pywhispercpp ($GPU_BACKEND backend)..."
if CMAKE_ARGS="${CMAKE_ARGS:+$CMAKE_ARGS }$PYWHISPERCPP_CMAKE_ARGS" \
GGML_VULKAN=1 \
pip install --verbose --force-reinstall --no-cache-dir --no-binary pywhispercpp "pywhispercpp==${PYWHISPERCPP_VERSION}" --log "$PIP_LOG_FILE" 2>&1; then
pip_reinstall_pywhispercpp "$PIP_LOG_FILE" --no-binary pywhispercpp 2>&1; then
if verify_pywhispercpp_backend_install "$GPU_BACKEND"; then
GPU_INSTALL_SUCCESS=true
else
@@ -3054,7 +3104,7 @@ install_whispercpp_with_gpu_support() {
print_info "Installing pywhispercpp ($GPU_BACKEND backend)..."
if CMAKE_ARGS="${CMAKE_ARGS:+$CMAKE_ARGS }$PYWHISPERCPP_CMAKE_ARGS $CUDA_CMAKE_ARGS" \
GGML_CUDA=1 \
pip install --verbose --force-reinstall --no-cache-dir --no-binary pywhispercpp "pywhispercpp==${PYWHISPERCPP_VERSION}" --log "$PIP_LOG_FILE" 2>&1; then
pip_reinstall_pywhispercpp "$PIP_LOG_FILE" --no-binary pywhispercpp 2>&1; then
if verify_pywhispercpp_backend_install "$GPU_BACKEND"; then
GPU_INSTALL_SUCCESS=true
else
@@ -3191,49 +3241,9 @@ FALLBACK_VOSK_CONFIG
echo ""
}
# Distro python3-gi provides `gi`, but apt does not drop pip-visible
# PyGObject dist-info. `pip install .` then tries to build pygobject from
# sdist and dies (needs girepository-2.0). Same skip as uv export's
# --no-emit-package pygobject: install the other deps, then the project
# with --no-deps. Do not use requirements/*.txt hashes here (Phase 2).
write_pip_reqs_skip_pygobject() {
local dest="$1"
shift
"$VENV_DIR/bin/python" - "$dest" "$@" <<'PY'
from pathlib import Path
import re
import sys
dest = Path(sys.argv[1])
extras = sys.argv[2:]
text = Path("pyproject.toml").read_text()
def quoted_strings(block: str):
return re.findall(r'"([^"]+)"', block)
reqs = []
if not extras:
match = re.search(r"^dependencies = \[(.*?)\]", text, re.M | re.S)
for req in quoted_strings(match.group(1) if match else ""):
pkg = re.split(r"[<>=!~;\[]", req, 1)[0].strip()
if pkg.lower() == "pygobject":
continue
reqs.append(req)
else:
opt = re.search(
r"^\[project\.optional-dependencies\](.*?)(\n\[|\Z)", text, re.M | re.S
)
opt_text = opt.group(1) if opt else ""
for extra in extras:
match = re.search(rf"^{re.escape(extra)} = \[(.*?)\]", opt_text, re.M | re.S)
if match:
reqs.extend(quoted_strings(match.group(1)))
dest.write_text("\n".join(reqs) + ("\n" if reqs else ""))
PY
}
# Exports use --no-emit-package pygobject: distro GI remains visible through
# --system-site-packages. Install the locked dependencies first, then the local
# project with --no-deps and --no-build-isolation so neither step re-resolves.
require_distro_gi() {
if ! "$VENV_DIR/bin/python" -c "import gi" 2>/dev/null; then
@@ -3248,25 +3258,33 @@ pip_install_reqs_file() {
local pip_log="$1"
local reqs_file="$2"
if [ ! -s "$reqs_file" ]; then
return 0
print_error "Missing or empty pinned requirements: $reqs_file"
return 1
fi
pip install -r "$reqs_file" --log "$pip_log"
"$VENV_DIR/bin/python" -m pip install --require-hashes --no-deps --no-build-isolation \
-r "$reqs_file" --log "$pip_log"
}
pip_install_project_skip_pygobject() {
local pip_log="$1"
shift
require_distro_gi
write_pip_reqs_skip_pygobject "$VOCALINUX_TMP_DIR/runtime-deps.txt"
pip_install_reqs_file "$pip_log" "$VOCALINUX_TMP_DIR/runtime-deps.txt" || return 1
pip install --no-deps --log "$pip_log" "$@"
require_distro_gi || return 1
pip_install_reqs_file "$pip_log" "$INSTALL_DIR/requirements/runtime.txt" || return 1
"$VENV_DIR/bin/python" -m pip install --no-deps --no-build-isolation --log "$pip_log" "$@"
}
pip_install_extras_skip_pygobject() {
local pip_log="$1"
shift
write_pip_reqs_skip_pygobject "$VOCALINUX_TMP_DIR/extra-deps.txt" "$@"
pip_install_reqs_file "$pip_log" "$VOCALINUX_TMP_DIR/extra-deps.txt"
local extra
for extra in "$@"; do
# uv normalizes underscores to dashes in export filenames.
case "$extra" in
vad|vosk|parakeet|faster_whisper|whisper|dev) ;;
*) print_error "Unknown dependency extra: $extra"; return 1 ;;
esac
pip_install_reqs_file "$pip_log" "$INSTALL_DIR/requirements/${extra//_/-}.txt" || return 1
done
}
# Function to install Python package with error handling and verification
@@ -3340,13 +3358,13 @@ PY
# Install test dependencies
print_info "Installing test dependencies..."
pip install pytest pytest-mock pytest-cov --log "$PIP_LOG_FILE" || {
pip_install_extras_skip_pygobject "$PIP_LOG_FILE" dev || {
print_warning "Failed to install some test dependencies. Tests may not run correctly."
}
# Install all optional dependencies for development
print_info "Installing all optional dependencies for development..."
pip_install_extras_skip_pygobject "$PIP_LOG_FILE" whisper dev || {
pip_install_extras_skip_pygobject "$PIP_LOG_FILE" whisper || {
print_warning "Failed to install some optional dependencies."
print_warning "Some features may not work correctly."
}
@@ -3384,25 +3402,16 @@ PY
local WHISPER_INSTALL_SUCCESS=false
# Install PyTorch and whisper
print_info "Installing PyTorch..."
if pip install torch torchaudio --index-url https://download.pytorch.org/whl/cpu --log "$PIP_LOG_FILE" 2>&1; then
print_success "PyTorch installed successfully"
print_info "Installing openai-whisper..."
if pip install openai-whisper --log "$PIP_LOG_FILE" 2>&1; then
# Verify the installation by importing the module
if "$VENV_DIR/bin/python" -c "import whisper" 2>/dev/null; then
WHISPER_INSTALL_SUCCESS=true
print_success "Whisper installed and verified successfully"
else
print_error "Whisper package installed but import failed"
fi
print_info "Installing pinned Whisper and CPU PyTorch..."
if pip_install_extras_skip_pygobject "$PIP_LOG_FILE" whisper; then
if "$VENV_DIR/bin/python" -c "import whisper" 2>/dev/null; then
WHISPER_INSTALL_SUCCESS=true
print_success "Whisper installed and verified successfully"
else
print_error "Failed to install openai-whisper package"
print_error "Whisper package installed but import failed"
fi
else
print_error "Failed to install PyTorch"
print_error "Failed to install pinned Whisper dependencies"
fi
if [[ "$WHISPER_INSTALL_SUCCESS" == "true" ]]; then
@@ -3586,10 +3595,9 @@ PARAKEET_CONFIG
print_info "╚════════════════════════════════════════════════════════╝"
print_info ""
# Ensure requests library is installed
print_info "Installing requests library..."
pip install requests --log "$PIP_LOG_FILE" || {
print_error "Failed to install requests library"
# requests is already installed from the runtime export.
"$VENV_DIR/bin/python" -c "import requests" || {
print_error "The pinned requests library is not importable"
return 1
}
print_success "requests library installed"
@@ -4530,7 +4538,8 @@ run_tests() {
# Check if pytest is installed in the virtual environment
if ! "$VENV_DIR/bin/python" -c "import pytest" &>/dev/null; then
print_info "Installing pytest and related packages..."
pip install pytest pytest-mock pytest-cov || {
local PIP_LOG_FILE="$VOCALINUX_TMP_DIR/test-deps.log"
pip_install_extras_skip_pygobject "$PIP_LOG_FILE" dev || {
print_error "Failed to install pytest. Cannot run tests."
return 1
}
+3 -1
View File
@@ -151,6 +151,7 @@ verify-release tag="":
# when you want newer CPU builds (torchaudio on the CPU index lags torch).
lock:
uv lock
uv export --only-group installer-build --no-emit-project -o requirements/installer-build.txt
uv export --no-dev --no-emit-project --no-emit-package pygobject -o requirements/runtime.txt
uv export --no-dev --extra vad --no-emit-project --no-emit-package pygobject -o requirements/vad.txt
# One export per selectable engine. install.sh installs each of these as an
@@ -168,7 +169,8 @@ lock:
uv pip compile requirements/whisper.in --generate-hashes --emit-index-url \
--index-url https://pypi.org/simple \
--extra-index-url https://download.pytorch.org/whl/cpu \
--python-platform x86_64-unknown-linux-gnu -o requirements/whisper.txt
--index-strategy unsafe-best-match --universal --python-version 3.11 \
-c requirements/runtime.txt -c requirements/installer-build.txt -o requirements/whisper.txt
# Compiled rather than exported: what the AppImage bundles on top of the
# lock, and what builds it, are pinned away from uv.lock on purpose --
# see requirements/appimage.in. --universal so one file covers both arches.
+14
View File
@@ -83,6 +83,20 @@ docs = [
# --only-group lint` installs them without the project, so the lint job needs
# no portaudio/girepository headers to build pyaudio and PyGObject.
[dependency-groups]
# install.sh installs this wheel-only toolchain before any source builds, then
# disables build isolation so pip cannot resolve another unpinned environment.
installer-build = [
"pip>=25.3,<27",
# CPU torch still requires pkg_resources; this cap applies only to the
# installer venv, not build-system.requires used by Arch's toolchain.
"setuptools>=77,<82",
"wheel",
"meson-python>=0.16",
"cmake==3.31.10",
"ninja==1.13.0",
"repairwheel",
"setuptools-scm>=8",
]
lint = [
"black>=23.0.0",
"isort>=5.12.0",
+109
View File
@@ -0,0 +1,109 @@
# This file was autogenerated by uv via the following command:
# uv export --only-group installer-build --no-emit-project -o requirements/installer-build.txt
altgraph==0.17.5 \
--hash=sha256:c87b395dd12fabde9c99573a9749d67da8d29ef9de0125c7f536699b4a9bc9e7 \
--hash=sha256:f3a22400bce1b0c701683820ac4f3b159cd301acab067c51c653e06961600597
# via macholib
cmake==3.31.10 \
--hash=sha256:1debc3a0823ce5d8d1bc17154599bbbb337c2681f93622b618bc78f46576e42a \
--hash=sha256:2f766bb46367e5e0559fa33184653754bce044583a06014dcaebf8e6dff8a1f1 \
--hash=sha256:3c17bb24dba15f8ecc3fd706afe04264410ef88796f4115c119327c961d5dc57 \
--hash=sha256:422a54711aa977af19d59b8f6010354cdda0b72a2e6d702b6d892e3e2cdf98a2 \
--hash=sha256:4cefb0a28ac1268b4eed4b595bf3aaff8de9704089066027700ec36584eccab8 \
--hash=sha256:678fc23db37cc69f01e18eb28790450ecc9401fd2fcd43364cc18f92330c12c2 \
--hash=sha256:6970bb75c4dfc28cc31ff0cd848194d09094ae00d605181e1345b2ff70b61050 \
--hash=sha256:7c300e4ae68fbc1414a85505f7feb262cee82ff3304a286885ebf803b11a997c \
--hash=sha256:8d2ec5fc45d305227020c82213140a51a0cebe3c84f0299036f05716b3a52f60 \
--hash=sha256:91410816db3beefe2f6032d721f9978c98dc7646e9992c0325486597164fab81 \
--hash=sha256:a4a5615f31f692c9b9aa8b365704e4b76172348af6fa40e16fea3f118bb01194 \
--hash=sha256:a7864605238759a4ae8e3bd1fda2bb03978e3e37df310852662dcf53866413c8 \
--hash=sha256:ad697643a00d9ba85179590a383c4f7401169b55ebf4b8b2938daf28c6bdeb6d \
--hash=sha256:b059a1810a2ce766b3e531bdc8d730bc192e260a9fa7dec7a0eb7a053d6063c7 \
--hash=sha256:b331984de38dbda22d676f8812c8905526341ba7b397fe8c359255ff4d051193 \
--hash=sha256:c2e5361dea9754ed3b06cf834894fb47dcbe7036d5e5d87acaeb10ff3dd5fd10 \
--hash=sha256:e135d5f1e59f1dc1c80eea87321977d6c0eff86cb601c28e0965a1dd457ea587 \
--hash=sha256:ec3d14a0e72e401b3665034dc37901df17f0b4e9c5b163be6cfedfb93470ac0f \
--hash=sha256:f1ea1fe826355560e8976c3d5794d9357444209bc0e0d56676c71e6a571fd474
delvewheel==1.13.1 \
--hash=sha256:1b3bc696193a57e322b8bfd644de240be6e003066aae44cc3d5aef8cbee22ca3 \
--hash=sha256:ae445f35f411c367f5b350431ac5f1435af8128bff31ccf34035a409704da8c6
# via repairwheel
macholib==1.16.4 \
--hash=sha256:da1a3fa8266e30f0ce7e97c6a54eefaae8edd1e5f86f3eb8b95457cae90265ea \
--hash=sha256:f408c93ab2e995cd2c46e34fe328b130404be143469e41bc366c807448979362
# via repairwheel
meson==1.12.0 \
--hash=sha256:71f133147fa0fcfe8f4df49fa1045771064947834538409e5d97b3613aac8b4e \
--hash=sha256:88afe0c20e52030218924ac37d0c81c59b4b5f3ae3752c8c6d7470c7d365886c
# via meson-python
meson-python==0.21.1 \
--hash=sha256:270bc9b78957c47e0aa1758ad616dba3f943d8f9cbdb944d318c3c1c7a49e4bd \
--hash=sha256:78b3345dcbc0fed7b939e7e37a9faab35bddaae07bf62e7542c8ad479c395af5
ninja==1.13.0 \
--hash=sha256:11be2d22027bde06f14c343f01d31446747dbb51e72d00decca2eb99be911e2f \
--hash=sha256:1c97223cdda0417f414bf864cfb73b72d8777e57ebb279c5f6de368de0062988 \
--hash=sha256:3c0b40b1f0bba764644385319028650087b4c1b18cdfa6f45cb39a3669b81aa9 \
--hash=sha256:3d00c692fb717fd511abeb44b8c5d00340c36938c12d6538ba989fe764e79630 \
--hash=sha256:3d7d7779d12cb20c6d054c61b702139fd23a7a964ec8f2c823f1ab1b084150db \
--hash=sha256:4a40ce995ded54d9dc24f8ea37ff3bf62ad192b547f6c7126e7e25045e76f978 \
--hash=sha256:4be9c1b082d244b1ad7ef41eb8ab088aae8c109a9f3f0b3e56a252d3e00f42c1 \
--hash=sha256:5f8e1e8a1a30835eeb51db05cf5a67151ad37542f5a4af2a438e9490915e5b72 \
--hash=sha256:60056592cf495e9a6a4bea3cd178903056ecb0943e4de45a2ea825edb6dc8d3e \
--hash=sha256:6739d3352073341ad284246f81339a384eec091d9851a886dfa5b00a6d48b3e2 \
--hash=sha256:8cfbb80b4a53456ae8a39f90ae3d7a2129f45ea164f43fadfa15dc38c4aef1c9 \
--hash=sha256:aa45b4037b313c2f698bc13306239b8b93b4680eb47e287773156ac9e9304714 \
--hash=sha256:b4f2a072db3c0f944c32793e91532d8948d20d9ab83da9c0c7c15b5768072200 \
--hash=sha256:be7f478ff9f96a128b599a964fc60a6a87b9fa332ee1bd44fa243ac88d50291c \
--hash=sha256:d741a5e6754e0bda767e3274a0f0deeef4807f1fec6c0d7921a0244018926ae5 \
--hash=sha256:e8bad11f8a00b64137e9b315b137d8bb6cbf3086fbdc43bf1f90fd33324d2e96 \
--hash=sha256:fa2a8bfc62e31b08f83127d1613d10821775a0eb334197154c4d6067b7068ff1 \
--hash=sha256:fb46acf6b93b8dd0322adc3a4945452a4e774b75b91293bafcc7b7f8e6517dfa \
--hash=sha256:fb8ee8719f8af47fed145cced4a85f0755dd55d45b2bddaf7431fa89803c5f3e
packaging==26.3 \
--hash=sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79 \
--hash=sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c
# via
# meson-python
# pyproject-metadata
# repairwheel
# setuptools-scm
# vcs-versioning
# wheel
pefile==2024.8.26 \
--hash=sha256:3ff6c5d8b43e8c37bb6e6dd5085658d658a7a0bdcd20b6a07b1fcfc1c4e9d632 \
--hash=sha256:76f8b485dcd3b1bb8166f1128d395fa3d87af26360c2358fb75b80019b957c6f
# via
# delvewheel
# repairwheel
pip==26.2.1 \
--hash=sha256:71138adf1f4ca900cdb7d289c21b7494329f2332b6d85f0e1c42108c0384ed3e \
--hash=sha256:f6ad667e89a1fe78046c8f13232b247200f5258d7828f3f7883d660878e0813f
pyelftools==0.33 \
--hash=sha256:660d82dcbeb8e83d1702bd97f223f761625da06111c0cc988eac6b8ab0c1b61f \
--hash=sha256:f215ad5f47d3f1373a21496a6c9e0707c622840d0622f23ff7ce08678b020036
# via repairwheel
pyproject-metadata==0.12.1 \
--hash=sha256:8809a4df6fe08279b39a8890669506ed3158e0617855ac9aff098fcbe772ae4c \
--hash=sha256:f7162d580a96386a8eb096da06215f981f547d1490f03055ef99e323bc2da427
# via meson-python
repairwheel==0.7.0 \
--hash=sha256:46083dad76e35595712ae593c1c9f112fb3f37a0e63268906e6de8182de55122 \
--hash=sha256:7fff43ed5abbf9710ef5ea6478c10cfd551aae043f445fd46307d4b602674ce0
setuptools==81.0.0 \
--hash=sha256:487b53915f52501f0a79ccfd0c02c165ffe06631443a886740b91af4b7a5845a \
--hash=sha256:fdd925d5c5d9f62e4b74b30d6dd7828ce236fd6ed998a08d81de62ce5a6310d6
# via setuptools-scm
setuptools-scm==10.2.3 \
--hash=sha256:7fcf8ff55c95eb8b572a23c81495e5559b9b90f3e82fcf0952bb76c37de27a81 \
--hash=sha256:f179ed3e2a63cf5823e5ee9aa9ca08386219400443a0553224d72dde3f206b44
typing-extensions==4.16.0 \
--hash=sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8 \
--hash=sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5
# via repairwheel
vcs-versioning==2.4.1 \
--hash=sha256:b7089ec9bef67b2cad82148366e8eac4d63173f440ec62628282b59eb96bbcb0 \
--hash=sha256:d4575de3115ec9434393c87c80ffb0eb98a16056bfe2b11ce0f3a97aff67fe0a
# via setuptools-scm
wheel==0.48.0 \
--hash=sha256:3217dcc807155e45db462d7ef2431f5ddda0d7273b700d05a67b271ceb1287ab \
--hash=sha256:94800765601e9171bf5d58d066e640662842bcedcbab982b2c90787a2c987322
+3
View File
@@ -4,6 +4,9 @@
# CUDA-bundled PyPI wheels can never match, regardless of index order.
# Bump these pins together in step with each other when regenerating
# (`just lock`).
# Resolve across supported Python versions and constrain shared packages to
# runtime.txt / installer-build.txt; otherwise this export can downgrade the
# runtime (or select a numpy requiring a newer Python than the installer).
#
# The extra-index line below propagates into whisper.txt so plain
# `pip install -r requirements/whisper.txt` resolves against the CPU index.
+301 -25
View File
@@ -1,14 +1,195 @@
# This file was autogenerated by uv via the following command:
# uv pip compile requirements/whisper.in --generate-hashes --emit-index-url --index-url https://pypi.org/simple --extra-index-url https://download.pytorch.org/whl/cpu --python-platform x86_64-unknown-linux-gnu -o requirements/whisper.txt
# uv pip compile requirements/whisper.in --generate-hashes --emit-index-url --index-url https://pypi.org/simple --extra-index-url https://download.pytorch.org/whl/cpu --index-strategy unsafe-best-match --universal --python-version 3.11 -c requirements/runtime.txt -c requirements/installer-build.txt -o requirements/whisper.txt
--index-url https://pypi.org/simple
--extra-index-url https://download.pytorch.org/whl/cpu
certifi==2022.12.7 \
--hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18
# via requests
charset-normalizer==2.1.1 \
--hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f
# via requests
certifi==2026.7.22 \
--hash=sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775 \
--hash=sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55
# via
# -c requirements/runtime.txt
# requests
charset-normalizer==3.5.1 \
--hash=sha256:00668ebb0609751758682eb0b5857e7c35b9f00e84dfdef062e103244ec94d45 \
--hash=sha256:012a22b88a77ca2e59b98ac5889b0deb604147666032f45e6d6e217634d2550d \
--hash=sha256:01e93745f7f219b703b60ba7afead36cfc4242782be5af484673fc500df12da5 \
--hash=sha256:04368edf83514385ffc3e1cfd4546e595f4f1272dd23ba437a93a9cc3741d47b \
--hash=sha256:0722590aabf9dc6a6c0343d523c05458fa2b5047dbe6302fd526bb570600753f \
--hash=sha256:07ffd07412fc5d5e84cd8952acf9ff7e4ed7a708e69d1bada19d8ba91711353f \
--hash=sha256:09a7bba9f739468c8e78c36a75c33768e53cb1959fc638f510454c14683f00d5 \
--hash=sha256:0b2b1b3fa5670c127b246df1d0c059defd41f689a868a3b9d79df9b1cac42d22 \
--hash=sha256:0c6dfb5ca6723eeed15aa8e564a014d69fcb8812f94eef11fe3631e0508199f5 \
--hash=sha256:0d929fc574b4d6fd9e7c0f5c2ede8716a41911923aa7fa5fce38e0818aa4a1ac \
--hash=sha256:13e3afe97712e8887cd516e960c63f0b93122971e5b5e4b2622fe7701771e838 \
--hash=sha256:15f024313246a4ed976c60f440bb8d257815513a681d212ff74fd46f7d715a90 \
--hash=sha256:195ce897c6153c0700078142cf8efe3e6454ca4cf4357499e4078dfd83396626 \
--hash=sha256:19a3dd5aa73cef1c99687c4fc57db016a9c17104ae1185da88ba566a5d3bebe4 \
--hash=sha256:1d1c7a53a6c2103925cdd6d7229f8c567379f211c869793df679f2e9f738c369 \
--hash=sha256:1f5883d77fd409a261abb5dc8ccbe335720d798b1de4abb3b1d47ccbbc76b53b \
--hash=sha256:21b82d8082f6f5e7f456ef0bd16323d08de1266efbfeb476e64b2a91d1471a4e \
--hash=sha256:252d099029bcbea642f2a06c4ed5046bdf8b5a8150b64afa5e027e88b106e5ee \
--hash=sha256:256dd4d85d9e4dc595e2bc983c980e73f62ddeb3165c58b4c3dfe78c5c8548c1 \
--hash=sha256:26422d45fd13551cf564c58932f7d72b4f58b93b0fcf18c35ba6be12b46bb102 \
--hash=sha256:2679de311c7946dde5d3b6f44941844133ff5c7cb86099c0061ab1e8901c20a8 \
--hash=sha256:29880d17a8eb0b5cfdfd8944b468322928059aa35f1f5fa8ff22b149ec0b42f8 \
--hash=sha256:2bced4061f000f7187254a02ad3433ae17eaf991747ceea2f478422590a5bba9 \
--hash=sha256:2e9cf9253119d8e5d111f05d71626786fd3d6193817316eab1ca088cdb8593cf \
--hash=sha256:2f06b7eae9dbe77fe1d644ca244dad508de8d302870a43f3c559b521270938a0 \
--hash=sha256:2f293479cce755c75f1697e87c409b7ae4c555c7dfecb6e988ad13abba943031 \
--hash=sha256:329fc3ccb63ad22d867d84c2adea759a64079a37ba4a343433b02c7a2816871e \
--hash=sha256:343fb4f2821043bd87095f7b08a1a181febc8e36ac64212143bbfd0a0e1bc235 \
--hash=sha256:3588e376b3ea2eea84976f67273d679f229e24c66dce7b82ae45aef04ff6e072 \
--hash=sha256:35aea775dc2bd5f54cd84a1cd2696cc3207c479cb9cf0bd346f0d343e4300ddb \
--hash=sha256:35fe081843b35aad20ffeccec3eeffbe637b15d14f3fb22cc1b59cd8ec17e93c \
--hash=sha256:36047af20e17097c3bb9476c2b7655f2f7aa51322c0ba58c07695bedf755a950 \
--hash=sha256:3617ac3cfd8b9888f145ad89dd6e692285834b0201c6074a5eeaad3fd4d668c2 \
--hash=sha256:366ec70f5547c640d3ce1985722490f23faf4eb5216a7eeba78277490e78dacb \
--hash=sha256:394fea06235c8543390050ed5f529187074b029fb027213f6c46ac11ab5d950e \
--hash=sha256:3d27167433c0d5f18dc850f07d0b3816221984fecdc405d6c157a6f0b8f8e9e6 \
--hash=sha256:3e5e1224c0a6a90e05843e07adfec669edebec17801c67072f51e59561d63c0b \
--hash=sha256:41876ee62a3dddf48ff1121ad8f0798032aa03f2fd35f21f34a4cab14f18d8d2 \
--hash=sha256:433c5a81eade63b47e522303bad236f59dba55ea6951746f5558355eeed8c75d \
--hash=sha256:4582c27e8c889d64811987b5967fbd3ae0c823fe1fd933b543d55ac20bb475fa \
--hash=sha256:485a0d363cafefcd2538a73c7c838daa2035f09b2c9f9b5e3133f80c6aeb84c2 \
--hash=sha256:494b70049a4d69aec6e8137c13af4cf8db8c9f9820a1392ac293b0dd2987a818 \
--hash=sha256:496846868fea80e479324862fa877f02411f2fd0f83b79ccee2607aa68b2a032 \
--hash=sha256:4abdc5f9ad448c1ecbfae2974b820535d6bc6e7eef63babbab3d81cf46968c71 \
--hash=sha256:4b599739b93b2cbeded49645ae3c8d1405c29ddfbceac1545c87a3f9580a9e96 \
--hash=sha256:4bea7f8ebe90bbd7f0e4a2de42ca6924ba23e3e76418c408ff82f1d46fabd687 \
--hash=sha256:4c4fb141a727957c93edfe5c32a26ceb6b5f6461d67146e2d39f51e16170bea8 \
--hash=sha256:4c9548dc78002099910abaebc0a72ac58b7d30931869e0351c09b507dff4ece3 \
--hash=sha256:4d26f14f041e83dd8edfd61f4cd4fa7285d31798b5bf1f28e70c367ba6c41d61 \
--hash=sha256:4f298bdadb8f0b9e5672877f647d1be9373ef5320c9e2f049795e26cad28b6a9 \
--hash=sha256:52ec005752a56ae79547a05c0139ca2501a0c866390b6115008456b9f0e7cde1 \
--hash=sha256:55261ac0d2941c42f196dd576f543d87a8ee03cd6f5e30dfb4d807b2e3b9121a \
--hash=sha256:56490c595a28b1bb27dfc583e816152a9767721ef58b2c03b13f954d2f707420 \
--hash=sha256:58d3e12c88e0950bca850ae1f7c256055c097639c2edb9eb123af9807d8b15e4 \
--hash=sha256:58d4aa13a59c969dbfdf9e6a9560e242cbfd9e8a8f50c2747714df1a423adf65 \
--hash=sha256:59171c6e45bf07d0d5cab3b0bf81d945035530f6873398b3b531c31184d46663 \
--hash=sha256:5b6d1386bf0096d26d3a863dc0a487a5b4eb9aa93cf5ba69683d29dde6b9d60f \
--hash=sha256:5c0ea61a470e070686aa30892fed79e297d2c8d0ab46b8bcdf027d38c51da591 \
--hash=sha256:5c84bec0ab5ae0c64bfe73a7d2adcb5ce73b467523fc27fd6a28ab2aa6cbe35a \
--hash=sha256:5ca0555312ae2fe82715cada7fac375530c2f3349e1eaa1bcb33d0283ac79a18 \
--hash=sha256:5d8531a6569d025f68e2321e7638fb7978f23db58e5f69f56913837aae03816e \
--hash=sha256:5e2d0e146dcb57034f8b97dc58d2d512cb90aba253960ce449f695fec6a82c6f \
--hash=sha256:5fc45d653ea8c9a20479167e11d4a0f8cb2fa3470737ab6f9c827532313187b7 \
--hash=sha256:6117b84ea48435e5356dc737f5121485c30920ba43375fa7b434fd753df0eac3 \
--hash=sha256:6199d5606e2bbf2b096cf64d03f8b6790c91081d5ac866b8e7bb6422738cc60c \
--hash=sha256:62b55f6722735a6c472f88361cde6640608773d9443cebdbb51abf436a1fcdd3 \
--hash=sha256:687c9ca3035544b113bea2055e180af96fb63c0c476e22a9180f51925186e7b7 \
--hash=sha256:6b7430cf5728e68f6c462254009a6ef4086e1bea43cf2f57aa9c55fb4f50ff96 \
--hash=sha256:6ba32c4d2abf1d2fe7cf27d280f4cca5664233b0f885549c7761719eb977f486 \
--hash=sha256:6c9cdde8becb25a7fde49924511aa2644d6f8081cc8df8e9452724303348d8e3 \
--hash=sha256:6df0ec430f9a831772c23ca5a224cba36517a58a84bb32c32bb59a9fa67c47f6 \
--hash=sha256:6e2912d4babbc65196ac13c2f53468dc57fb8b9c25ef913e8c59ddf7c6dc0e1b \
--hash=sha256:6e5e4d73d588ca5ed09df1b7dcd1b203d1df3c542e3f50d126c947d432b10731 \
--hash=sha256:70055ff39b97c99e7ae40ea3e393fb62aa2e44dbd9b29f8d14f42fb0025c3959 \
--hash=sha256:706bfd38730a5ac7a365793269a00f4e988178cec121391f4248d84ad8c972e9 \
--hash=sha256:7235dc28fc6dd9d832ac7c7bce95367dedb85929f17368a0c2bee1e080b9acbf \
--hash=sha256:774d157f112367ff4abd29019f38f023c24e00e56edc7829c20e358a5a913ad8 \
--hash=sha256:77efcff2b23071c349402ac1066667a3d011f62398d81408c9b88ad991747c9e \
--hash=sha256:789b8982559ae28dad2356519f841655756cdcd96616410590ae0b17454ee64f \
--hash=sha256:7ac76cf9afd34929d76eb7fcb63be476a4853d8a96f0dcf2d0db68a0cbdf9885 \
--hash=sha256:7c0c10730342b0c9b35dd1d619beb8214e520bd96a1f870f452680b238aab3e0 \
--hash=sha256:823f82903d189af463d7df250ef1f7f696f3cee08cc8d91deb565e8d425f6506 \
--hash=sha256:838648accb3a7fd9803fd45c87bce8509648eb0c11bc34e216141300977244f2 \
--hash=sha256:854066be00447fa8de2ccbbe893e2ffc4b123ef16d897af794c1e18bd4a714b0 \
--hash=sha256:85d5855daafc240cc045c026d7a15fd198a09b0fc8ff6f5ecbb5297b509cb11e \
--hash=sha256:85de3134b5379856e323ba37c19c9256d39425f7b76a63af52b09fb4664c2e8f \
--hash=sha256:87e4f41d375c0b9be2fb5251aee4b8a689169e134535aed81bf085c3b647451e \
--hash=sha256:88ca277405c2d3b71c4e1c2ee0e7966e807bcba86a69d11e19ba199d18ae4491 \
--hash=sha256:88e85ab89cb822c1e635f51d6d32e488f94e002e70e2f492bdb8b945543f345a \
--hash=sha256:8ac8c94b6539074e0f40899301273ac8402b9b3e01c7b7ba269ff30340aaaf20 \
--hash=sha256:8fe532b3c966d1fb794e0698e4589d0444017ae77fc0b31edea13c0e35bcc449 \
--hash=sha256:9085f87b0e38a2b92b8923059b4e8789fe40d9279712d15dcc670048d77079af \
--hash=sha256:90b7481fb62fbe172c558bc6fd1c4c98d82004a54a7551f20e11ac9bf0b8708c \
--hash=sha256:92caef967d287a407085d61176fce4012b1dd62daed4eb6d5ceb26d3d2538712 \
--hash=sha256:9362dd90aa7dab48c0054a21187791ccf05473f7dba5d92b8033ae62164675e7 \
--hash=sha256:94d78ecec2605a8d0398b0f365d5f12a63248438516f5dac536a5eff7337df4a \
--hash=sha256:94fbf1c0c6cc0d3d5e50f9a9313a8cdca90dd696d34b381cd1704f8c9e939f20 \
--hash=sha256:950f23cb393f85543777b0433f082cddd25b51ab398eac7971146495679efe5f \
--hash=sha256:96eefc178f8636b9c760c5829345307fd81cfae9ab1e80997dbddeb0f54ee9a3 \
--hash=sha256:96fef3e886d6a9874b14f27fc193fbdc69d5d8035783d86aa4e1cea594e695f9 \
--hash=sha256:977cdbd483a9cff38179bea4fd754289a6f2195c7abd414aba85410b3e66cc5e \
--hash=sha256:978eab16f55b4ab2c2a745be9a0a840bf8f09a7f227d9c76eb30214d078865a5 \
--hash=sha256:994e883d17c559cdfd38c84003c8b27d25424a1077272a17e7cd27bfe0bf57b2 \
--hash=sha256:9ac4444d8d4fd4c4bd08bf451ed3167aa9e7ec6cdb41b648794f1d1103652e36 \
--hash=sha256:9b5db6052055d34d41230fb78d7c439c23dc536a9896f6cb039e8dd92cfc1263 \
--hash=sha256:9d9a0dc7cbe9bec24c3f767c9122c41fe5a1bc43f47cd099d00d393e09769de4 \
--hash=sha256:9dbdd9205662134957cf0c324f639bdc5031c0ca056e2369e238db75187c0f11 \
--hash=sha256:9eea3ab2597a5e65fe65296e2d6a84570845a6b55532d90333d740d48bbc850a \
--hash=sha256:a2028475ba855475b8b4d3cfeb4994269c967aea8b9892dfba907f4263a863a3 \
--hash=sha256:a3a370082ce34d0612f421e15fe011c53bb1feff21a26d06ad4fb244dab5a375 \
--hash=sha256:a545775cfe815855ea32d7c27731d79da358ef2055b4a25830231b1622dd18aa \
--hash=sha256:a5cbd90ecf0fc62e64726917ad083b73001f0563657a87ec3c0b504e277dc90d \
--hash=sha256:a6d095662e73e74f0a49988e0593373e243e3a52e27bfeea0a859e88acf4a0f5 \
--hash=sha256:a6dac12ff6b846103483683f60c5f8fee205121adc58ffd87e90a90a3af69e99 \
--hash=sha256:a951ad59cad9145664a730d3036b40b844e74d2d3683da40111463cd3a83845d \
--hash=sha256:aa1099b956fb795e686d073568f6dc002a0bb89765ea6d5b055dd7d9bf1b116c \
--hash=sha256:aa2bb0b37202dca27175591f761108b5d34096ade1191ffe4808bdf6b1571488 \
--hash=sha256:aae2ee51122d3ae968a3837d97dc24a0aeebb0dea23694422cd172bd30017cd6 \
--hash=sha256:ab743e9bc90c1f73552ec33e10e3331315acd2c397b36065b591b0181de533cc \
--hash=sha256:ac00177c4831ffa650f8609e4bdddd5fe09c03b1c0c47acece7e6ea20421598b \
--hash=sha256:ac13b004224fb341e1e25a1ed5e19d32f57cdb2a403e01f003b46f051a550f6f \
--hash=sha256:acaf604462bf330b0d07e7a07c1d6e4adac79e5fb13e9c5140590542cafacc00 \
--hash=sha256:ae31a1a1db2ee6cc2942fccaf695c934bc7f3db9f2133a3fef1f367cf1a4ab10 \
--hash=sha256:ae4a097991662cd4fff0ddc74e0fe7874f82e00042fa0ea00855645ed0c79598 \
--hash=sha256:aea996a6aba25260827c9ea511d1addfde2da9eb686ac961838509086188b7e6 \
--hash=sha256:b39b69b347e5e47a3b5b8cfc005c68c1ba347474e3960236c4944a8ecd174962 \
--hash=sha256:b54e7e13267d49ffbfe68e25b3cbd774dab38fa37238f71265e91b36146eb21c \
--hash=sha256:b9af956078716df40d985fb0dfeb2c2120c5ca92ba4ff4b388acfd01cdc14d08 \
--hash=sha256:ba2f37ee79e6338845261a3c5b1784e5d1acdff2c0785b284f1b633033d136ab \
--hash=sha256:ba501e667c17d8411f98e67a022d9604ef179aff0e459b7e292c796837c13573 \
--hash=sha256:baf3775a2635e5a11fbd5e4e64ee69c7e86875d224a5c72aca4c141064589a90 \
--hash=sha256:bb57753e36e4855b8ca375069482250a6246372331a3e4f3407eaebb007443f5 \
--hash=sha256:bd6c173f04743d483881bffa1478d5a4624475b8cd1d2194956a75548e191c18 \
--hash=sha256:be47f99644b208bff7766314013f9acf57b056b04191d570d68ad14022cf5b1d \
--hash=sha256:c010f5581d9c612804cc59fcf7b524b707fbcb72828551237ab545bb5c7034af \
--hash=sha256:c1dcc36dcb96abc02236e182d17e0f71430152a6c2c7447421da2d2dc144edea \
--hash=sha256:c428c6c31eb5f4277d7f8eccaf767fbd548ddd5ce3c8b4f4cbbfab3d96b5904c \
--hash=sha256:c658c50ac0c98cd755a2dd50b7977d3bca7df401dcc47fbdfa87db53ef7d4e8b \
--hash=sha256:c71fb0d56c920c269cd3e2e3fe7c610e3f1fdb21a6ce60efa6430ff63676cea6 \
--hash=sha256:c7b742bf31c88566b4bb6335a7f393bb322e580b6bb98df7bd0c25e6e3519ce8 \
--hash=sha256:cc0329df4caaceb950d2f580b5ac716a377f7059624a0bafaeaf8a218c6ed774 \
--hash=sha256:cc5d36d96478aa9c60654bd932525bf32964c62a7281eafdf16d85003a8d6004 \
--hash=sha256:ce854f5f478050ade5a238731c4ca985a7d3b3cb53ff600a9b5c3b689b5f0a7a \
--hash=sha256:ced3fdd71aaa83ce593746c2edb42b7a59cb4c19c8b5c407781c72e493aae55a \
--hash=sha256:cee5dd7c6fb5dd52a0fe2a740f9bc6e3593f5f8b1788bde49de02086f30182b2 \
--hash=sha256:cfa1c0cc3a8f9f53f1243a5a99ac36fd003880199383b37672e86ddda9cb07e2 \
--hash=sha256:d1ee1e296209fdce05b81b663250eefa02213a2da7b41bf26f7829b8ba3545aa \
--hash=sha256:d59b75732e9b6f27388e10c14b0259cc5f2e48c78627d185e6a177b58ad3cffe \
--hash=sha256:d63600d620ad0064c3a748b950ac5ea38a80190e5498532efefa4b7b3f1da1f3 \
--hash=sha256:dd732602a7009217f658d5863d12d79d373a4de0eebc111094bcdd3bb8e0a6cc \
--hash=sha256:e06efa066f7dbadbc84ebc126a97c452a6451dfcf589d89d788484949e1cf795 \
--hash=sha256:e199fb99720074809a7720f1c0b4d919eea8b87e88713e0f8f602f7bef543d9d \
--hash=sha256:e4b018dc5a0eee4676e38fe84a47a427816c590b93b55d9025274ec4d6ffc2dc \
--hash=sha256:e6621fb2a4988d6e53eedc455e5903e2679f3967b8acb3d639f1b63c14a2e893 \
--hash=sha256:e71c909f353863b2b89c83de2ebed71ea6d0df8a6ef65a128193c5e650766bef \
--hash=sha256:e90251c0c7bdd54a100a0dce3c07b7e637278c93af29dbf78ebb89a58c4bac7d \
--hash=sha256:e9fbdce1e47394b09bc9f26ab117dfc8d6491977a11d86f592bb42c779db2fda \
--hash=sha256:eb12fb2ba69ffa05f8695f61c69e591dc4b4a12ac3757ac8af8adb259bf56d17 \
--hash=sha256:eda059b6bc8bc0812d626fd91a7ce01bf583df0a61296eff390fd94141a34e30 \
--hash=sha256:f03ac127268b43ef4fe9e6ab6794a6794b49485a0cc0c1db79876d2f33f75bc7 \
--hash=sha256:f298e218441525d3794428b4c8b8fb8662c6d3ea79925d4807ee6b9a96a3bca5 \
--hash=sha256:f5542f9b941279d82d41eb0aa9f98eba36fe4df5c7086c651df7944935b37182 \
--hash=sha256:f6f7deae3feb4edfa2efaf7c574fe88cbf055038a6abdb40188e4fff66d5699f \
--hash=sha256:f9b1e28d0e8dbfa858abdba91d6b547beaf2df1a59bec6da6faae7b96a4991a9 \
--hash=sha256:f9f8405c2c758532c74fed975dbee57be1f31a6e865c031870c79a6ed3212ada \
--hash=sha256:fa48b1b63d639f9483e0633e092f5851e2348c352f1f9bb6c8182f87884ef876 \
--hash=sha256:fb78f6e7fcd8ad785d28cd577168bc1aaee827b25bb8755638f694794ea98f0a \
--hash=sha256:fbc597639158fd7c14d55e808718848319540f51b0e6746e3eefa59723a4a348 \
--hash=sha256:fce8cbd4997efeb450bd298b54f755dcdff18d496f7a5ddbb4867c6d7c88fdc3 \
--hash=sha256:fd0350afdc3aabd5576f60ea109228bd5538139713c7b094c5cd27c73a98bc6f \
--hash=sha256:fd0a274c0e5f9a21565cd9d3dd749b61f96b7aa1e20a93aa1ba4029518f2e5c0 \
--hash=sha256:fdb8a068947befafba9952162645dc2fecaeb400e64584829ed5e9b2fbe21a7f
# via
# -c requirements/runtime.txt
# requests
colorama==0.4.6 ; sys_platform == 'win32' \
--hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
# via
# -c requirements/runtime.txt
# tqdm
filelock==3.32.3 \
--hash=sha256:0ffa185a3540854c95caa7fa76b76cb219d907415e2c5dc9af25fd970563487f \
--hash=sha256:7f0ca4bcc0e181c60dbbd8aa9ab5b120ebb99e4e064e83636340056f833a1f09
@@ -17,9 +198,12 @@ fsspec==2026.7.0 \
--hash=sha256:b57ddbafedfaef7018c1ecab32aa200a9d7ca26b77965f64e48b70061249d279 \
--hash=sha256:c803c40f4cf860b49dea58ee3e1c33cb9c790520e233537e1340049f89b82a88
# via torch
idna==3.4 \
--hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2
# via requests
idna==3.19 \
--hash=sha256:5e0811a4383b21dc5838069f801c4fb62113b7447663d2530d2bd6e77b49bf15 \
--hash=sha256:815e7be7a7806d54abb586dc943addc79e8b2ee16915059658cbeff4b1b43bf4
# via
# -c requirements/runtime.txt
# requests
jinja2==3.1.6 \
--hash=sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d \
--hash=sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67
@@ -183,7 +367,84 @@ numba==0.67.0 \
--hash=sha256:f63d43db06b4756424d6d2484737c902e0ae944a0eec3e8b0b4de2c695b15caa \
--hash=sha256:f99f880ff25f418a67f9a1d00d0ddfbc63430f627b523e515085a592a7567f4b
# via openai-whisper
numpy==2.5.2 \
numpy==2.4.6 ; python_full_version < '3.12' \
--hash=sha256:001fbb8e08d942dd57599e781f2472269ee7f2755fae407b4f67b2f0b17da3f1 \
--hash=sha256:0280e0356c0829a18d9de1cb7eee50ec22ca639878d7240307ca0943d73cd2c4 \
--hash=sha256:043191bfa8eab18c776647b62723ac9dddece59743b13f49b2016094129c2b3f \
--hash=sha256:06ca2f61ec4385a07a6977c55ba998a4466c123642b4a32694d3128fce18c079 \
--hash=sha256:0a041d3d761dc3c35cc56ce0351506a02bcbc25f7b169f652435141a17db9096 \
--hash=sha256:0ab0a9c4ffb1a6d95ef519fe4247dba8eb6b18ad93999f76b7f657039acabd47 \
--hash=sha256:0c9136e14ed34a9e343a31c533d78a9813a69a3148332bce5e9821cb2f996e66 \
--hash=sha256:110f8b71aacb688ec69062bb7f6938a0f8acb01b7c1c4beb453c65b6d234584d \
--hash=sha256:112b06a867b235ef466ed3508ddf0238050df9c727cafb5301ac385b899189a1 \
--hash=sha256:17f9ade344e7d9b464a084d69bcf18fc691cb1db67c62ed80820bf4926d78f0e \
--hash=sha256:1e254a00cdf42b1e4d5b3d68d33af63268d41340d8885df2ab6470f2e1500147 \
--hash=sha256:1e978ec1e8bd0e0e4de6bb75de9d30cbb74db6b6a2bb727618613703ca0167dd \
--hash=sha256:25c692919ac5a01f170a3bfcd62d745b24fd095c353d50812637d6fcab442e75 \
--hash=sha256:260a5d70215b61ab4fadf5c7baacd64821842975eea312125ed3c39a6391b063 \
--hash=sha256:2803abfebfc990042cd494d8ce2d5f82e9d847af6d35ec486923aa19dbad5e73 \
--hash=sha256:29a287e0cf63ff528da061de6b9f64a4618da591ca1046aafc54062e40ca7eab \
--hash=sha256:29cb7f67d10b479ff07c17d33e39f78c07f71c40ef30d63c153d340e96cd3fb4 \
--hash=sha256:3213d622a0283a39a93d188f3cf72b26862df52fbb4ca3697f51705016523d41 \
--hash=sha256:33111801a01c12a8a1e3721f0a9232f8cfc8ae2c6b7098167e6f623c6073f402 \
--hash=sha256:357cc07a6d7b0b182ff02249616a03742827ebb1277546b5c7cd7f7620a45698 \
--hash=sha256:38efbc8de75c7a0fc1ac190162d892787f3f47b57cc291231aafee36b80982b7 \
--hash=sha256:4081eb135ac24158bd51cdfbef16f1c64df7063b1143f24731387137c092bec8 \
--hash=sha256:40fdc1ae7125e518ea98e53e69a4ebc27e1fd50510c47b7ea130cf21e5e1d42b \
--hash=sha256:4cfe66903cc32a9921a6733d96b19bb6abf310397581bbad89c228f5abaf0ee8 \
--hash=sha256:511dbaf848decaaaf4b4ca48032619fb3138710c4bf7da7617765edad1ef96b0 \
--hash=sha256:55cced7c52e981362f708ad635198e97a752dfba412cc03c23bbf3bd8d5cd662 \
--hash=sha256:56b39e5e0622a09a25bf5baf62f4bcf0cb8a41ae6e2819cf49bbc5a74c083f91 \
--hash=sha256:5dbbdb29840ca3d91ee0fece42fc29278886d908280bfec0a5846c6f901a3eb0 \
--hash=sha256:5f9fb9157b4ce2971008323afe46053787b526ef624fea915b261468a8421a0f \
--hash=sha256:6180d8b35af935aed8ece3a85e0a43f87393ae0ac87c8d2c8bd2c993f7270ef3 \
--hash=sha256:68a5124b13fa6cc2086764a20005d30bc0548146f7f5322f02fce212ca14317f \
--hash=sha256:68bb27509ac1b9a3443094260f6326150663b06abe40b73a2f81160623da5b67 \
--hash=sha256:6f41ae150c4e32db4f3310cdaf64b1593a03dbabe29eec77fc9b50fe64061df6 \
--hash=sha256:7265a2f3d436e54ef9f2b52b5c937e6be778781bd97a590319d7348f1c1ca997 \
--hash=sha256:72fbe16c6fac95aedf5937fa873445cec2110be35d8a4e9433d7501fd98dae6b \
--hash=sha256:7d92c3819208a60205a12a245c91ad70cb0a85336659b19b834205573ac8456e \
--hash=sha256:8155154c7c691289fe18f510b5d4657c68c67989f293f0535a91360392ff6538 \
--hash=sha256:81a1cca95ed5bb92aa8b10dd2cdc9a0d3853a50fad926c28b5d7e8ea54389627 \
--hash=sha256:89cd468399cfd2504718f0ba50e410dca55a170b61a02ad92bb18c8a65186e93 \
--hash=sha256:8ad03c0965fb3c692200e74d458ca28c1dbb4ce96f9a479a8aa041ad5fabca02 \
--hash=sha256:90f9849678c75fe7afa2d348ac842c168b0a4d3d61919687216dfc547976d853 \
--hash=sha256:948424b06129ce883307e8cff868c31396d8dc7630a59c61d70d98dbe70f222c \
--hash=sha256:9cd5ffd25db4e7ba6a375693b3fc0fc1791ec636c17db3720da19bde7180ec43 \
--hash=sha256:a0df0043bdb289bde1f62da130d20df23d58b45429f752bc7a8fc5325a225ecd \
--hash=sha256:a2c306dea656c12c68f51f4cea133cbe78ca7435eb28c735eac1d3ebe73be6e8 \
--hash=sha256:a7830bab239b79cda9c08c2da014761cafb48da6150e1da17ac06283f43b6089 \
--hash=sha256:a7c711e21628b52034bb5ab8d1bce291f752fcc5e92accc615778acee1ff4778 \
--hash=sha256:aaf159caa35993cb1f56fb9b8e4610d35758e7ca005412eb1daa856a78c9c4b1 \
--hash=sha256:ae506e6902902557576a26ff33eda8695e7ecb3cb36c3b573a0765dee114ebdb \
--hash=sha256:b507f5c4c1d508876d1819b6bf9a49d365b96320b5d4993426b33a23ca4b8261 \
--hash=sha256:bf162abab1c1a736333192707cef898e735a5ca00f38f27eeedf44b39d9e85eb \
--hash=sha256:c1a2af6c6ef86344a6b0db6b97834208bf598db514f2b155042439b62605601a \
--hash=sha256:c2d37ab77531417474168eb79d6d80b14f821a966818505d03013d0833edb7a8 \
--hash=sha256:c4fc99836233ea196540b17ab0983aff60ed07941751930f5f4d05bc3b3b7359 \
--hash=sha256:d581b735e177fdcdce6fed8e7e8880a3fb6ee4e3653a3ac6af01c6f4c03effc5 \
--hash=sha256:d6da64deb6b8ed903e7560180a92f2d804ee1ba5eeb849ac2748b8c1aba1f6d7 \
--hash=sha256:d8e8286dd7cea7895157318d1b91cdacac64c479f3cbc8dce548331728484751 \
--hash=sha256:ddea102b48f9e339f3948bf22040944184627a30fdf7f858667673b9c5f033c8 \
--hash=sha256:dfa20cc6ca228e6b155b11da03825975ce66aea520985dbbddf0f2a5a495c605 \
--hash=sha256:e3e5193ef5a3dc73bceee50f7fdc2c90dbb76c42df8d8fae3d1067a583df579e \
--hash=sha256:e3eeb0aabd6bd5ce64faae67e9935203a6991b4bc2a485a767fbafb2c5125f45 \
--hash=sha256:e5805d5a22fd19c8ccff10a9561f9df94436b0545619ea579db2d3c35294bce2 \
--hash=sha256:e85b752a1e912b70eaad4fafbd4d1238007ab221de2009b9a2f5ae7461239895 \
--hash=sha256:eaf7fa2de5c0be8ae6ff8e9bea2ccd725e980541244521d8d4b5f3354a27babe \
--hash=sha256:ebfb099f8dcf083deef3ac1ca4c1503f387cf76296fcb3816b66f5ecb5f54fdb \
--hash=sha256:ece3d2cfe132e7d51f44a832b303895e6f2d499c5e74dfbdb06ee246147a304a \
--hash=sha256:ed9749eef4cbd126da3dc1d6bcb3a57f5eb7ac6a6484146bdbf743f552dfc577 \
--hash=sha256:ede83e07a75dd06bc501566c1eca2afc0d61677c1472ac9ad93fdee6e638a48d \
--hash=sha256:ef4aea96ce4d3b074422cb4f2f64e216bf9e213004bb58ecfdf50ea02ea8eb9a \
--hash=sha256:f3a3570c4a2a16746ac2c31a7c7c7b0c186b95ce902e33db6f28094ed7387dda \
--hash=sha256:f407cb6b8e9d6d8c626bc73c945db1706035af8fd632295547bf1c9e46d092d6 \
--hash=sha256:f74a575920ab21fe304421a3fc28793d82e299cae9eccb37084e9fc7f3617c20
# via
# -c requirements/runtime.txt
# numba
# openai-whisper
numpy==2.5.2 ; python_full_version >= '3.12' \
--hash=sha256:0090ccdd57ec2703e9b49d0bf554767370581c1dd0a6b2bb2b2d9def317d042a \
--hash=sha256:078f9b027b478c9379b9677babbf0f8b8f1ecfada27636d7b9a93990c638739f \
--hash=sha256:07d4e89f3a9ab0a9ba24264ccdb642b3dd951b2281e8883a5481a4aa79cc31a7 \
@@ -251,6 +512,7 @@ numpy==2.5.2 \
--hash=sha256:f06571a052127dc1b4e8b83029b4d1b20daa2b64a31cdd181fc6bc774e9000eb \
--hash=sha256:fd0d703772bba096843785bd38371e31bb4a0c1151497ad5739d182114a73f7f
# via
# -c requirements/runtime.txt
# numba
# openai-whisper
openai-whisper==20250625 \
@@ -372,12 +634,18 @@ regex==2026.7.19 \
--hash=sha256:fe31f28c94402043161876a258a9c6f757cb485905c7614ce8d6cd40e6b7bdc1 \
--hash=sha256:ffd8893ccc1c2fce6e0d6ca402d716fe1b29db70c7132609a05955e31b2aa8f2
# via tiktoken
requests==2.28.1 \
--hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349
# via tiktoken
setuptools==78.1.0 \
--hash=sha256:3e386e96793c8702ae83d17b853fb93d3e09ef82ec62722e61da5cd22376dcd8
# via torch
requests==2.34.2 \
--hash=sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0 \
--hash=sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed
# via
# -c requirements/runtime.txt
# tiktoken
setuptools==81.0.0 \
--hash=sha256:487b53915f52501f0a79ccfd0c02c165ffe06631443a886740b91af4b7a5845a \
--hash=sha256:fdd925d5c5d9f62e4b74b30d6dd7828ce236fd6ed998a08d81de62ce5a6310d6
# via
# -c requirements/installer-build.txt
# torch
sympy==1.14.0 \
--hash=sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517 \
--hash=sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5
@@ -503,10 +771,13 @@ torchaudio==2.11.0+cpu \
--hash=sha256:fa0c22f58f60c3537b7d28ed2501e0995acb2a65d9af2708f21edaad67186cd8 \
--hash=sha256:fae220128cbfe060c663fbb2a1967b88c605f9eb49b535903cca694011662534
# via -r requirements/whisper.in
tqdm==4.66.5 \
--hash=sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd
# via openai-whisper
triton==3.7.1 \
tqdm==4.70.0 \
--hash=sha256:55b0b0dbd97462d06ebee91e4dac24ed4d4702be82b24f07e6c1d27e08cea220 \
--hash=sha256:7f585706bfddbdebf89daac705b2dfcc16890130727d3197ca62c732b4310953
# via
# -c requirements/runtime.txt
# openai-whisper
triton==3.7.1 ; (platform_machine == 'x86_64' and sys_platform == 'linux') or sys_platform == 'linux2' \
--hash=sha256:10ba85fa2cca4a2fbdeb36bf1cb082f2c252bda55bf9fccd74f65ec5bc647e68 \
--hash=sha256:2020153b08280415ec0da6607834e79166442147e78e144df06b508c75b186d2 \
--hash=sha256:3daf64305d6cea88d3334c65ebc9bcd0c64c9564a977084366aa768d57cbcf64 \
@@ -523,7 +794,12 @@ triton==3.7.1 \
typing-extensions==4.16.0 \
--hash=sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8 \
--hash=sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5
# via torch
urllib3==1.26.13 \
--hash=sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc
# via requests
# via
# -c requirements/installer-build.txt
# torch
urllib3==2.7.0 \
--hash=sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c \
--hash=sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897
# via
# -c requirements/runtime.txt
# requests
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env python3
"""Select committed requirement blocks without changing pins, markers or hashes.
The installer uses complete exports for normal installs and just pywhispercpp's
block for backend rebuilds. Missing exports or packages are errors, never an
empty successful install. Only the standard library is needed before bootstrap.
"""
from __future__ import annotations
import argparse
import re
from pathlib import Path
def select_requirements(source: Path, package: str | None = None) -> str:
"""Return an export, optionally retaining only one distribution's blocks."""
text = source.read_text(encoding="utf-8")
blocks = re.split(r"(?=^[A-Za-z0-9_.-]+==)", text, flags=re.MULTILINE)
requirements = blocks[1:]
if not requirements:
raise ValueError(f"No pinned requirements in {source}")
if package is not None:
normalize = lambda name: re.sub(r"[-_.]+", "-", name).lower()
requirements = [
block
for block in requirements
if normalize(block.split("==", 1)[0]) == normalize(package)
]
if not requirements:
raise ValueError(f"No pin for {package} in {source}")
return blocks[0] + "".join(requirements)
def main() -> None:
"""Write the selected export to the installer's scratch directory."""
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("source", type=Path)
parser.add_argument("destination", type=Path)
parser.add_argument("--package")
args = parser.parse_args()
try:
text = select_requirements(args.source, args.package)
except (OSError, ValueError) as error:
parser.exit(1, f"Cannot install pinned dependencies: {error}\n")
args.destination.write_text(text, encoding="utf-8")
if __name__ == "__main__":
main()
+349
View File
@@ -0,0 +1,349 @@
"""Exercise pinned installer calls, including fail-closed and rebuild paths."""
from __future__ import annotations
import hashlib
import importlib.util
import json
import os
import re
import shlex
import subprocess
import sys
import tomllib
import zipfile
from pathlib import Path
import pytest
from packaging.requirements import Requirement
ROOT = Path(__file__).resolve().parents[1]
INSTALLER = ROOT / "install.sh"
SELECTOR = ROOT / "scripts/installer_requirements.py"
def _run(tmp_path: Path, command: str, *, fail_pip: bool = False) -> subprocess.CompletedProcess:
"""Run real shell helpers with a recording interpreter in a path with spaces."""
venv = tmp_path / "test venv"
(venv / "bin").mkdir(parents=True)
python = venv / "bin/python"
python.write_text(
f"#!{sys.executable}\n"
"import json, os, subprocess, sys\n"
"if sys.argv[1:3] == ['-m', 'pip']:\n"
" with open(os.environ['PIP_CALLS'], 'a') as log:\n"
" log.write(json.dumps(sys.argv[3:]) + '\\n')\n"
" sys.exit(int(os.environ.get('FAIL_PIP', '0')))\n"
f"sys.exit(subprocess.call([{sys.executable!r}, *sys.argv[1:]]))\n"
)
python.chmod(0o755)
functions = [
"pip_install_reqs_file",
"pip_install_project_skip_pygobject",
"pip_install_extras_skip_pygobject",
"pip_reinstall_pywhispercpp",
"install_cpu_pywhispercpp",
"get_pywhispercpp_cmake_args",
"install_pinned_build_tools",
]
source = "\n".join(
f"source <(sed -n '/^{name}() {{$/,/^}}$/p' {shlex.quote(str(INSTALLER))})"
for name in functions
)
script = f"""
set -euo pipefail
print_error() {{ echo "$*" >&2; }}
print_info() {{ :; }}
require_distro_gi() {{ :; }}
VENV_DIR={shlex.quote(str(venv))}
INSTALL_DIR={shlex.quote(str(ROOT))}
VOCALINUX_TMP_DIR={shlex.quote(str(tmp_path))}
{source}
{command}
"""
return subprocess.run(
["bash", "-c", script],
env={**os.environ, "PIP_CALLS": str(tmp_path / "calls"), "FAIL_PIP": str(int(fail_pip))},
capture_output=True,
text=True,
timeout=10,
)
def _calls(tmp_path: Path) -> list[list[str]]:
path = tmp_path / "calls"
return [json.loads(line) for line in path.read_text().splitlines()] if path.exists() else []
@pytest.mark.parametrize("extra", ["vad", "vosk", "parakeet", "faster_whisper", "whisper", "dev"])
def test_extras_use_committed_hashes(tmp_path: Path, extra: str) -> None:
result = _run(tmp_path, f'pip_install_extras_skip_pygobject "install log" {extra}')
assert result.returncode == 0, result.stderr
(call,) = _calls(tmp_path)
assert {"--require-hashes", "--no-deps", "--no-build-isolation"} <= set(call)
assert call[call.index("-r") + 1] == str(ROOT / f"requirements/{extra.replace('_', '-')}.txt")
@pytest.mark.parametrize("editable", [False, True])
def test_project_follows_locked_runtime_without_resolution(tmp_path: Path, editable: bool) -> None:
args = '-e "project directory"' if editable else '"project directory"'
result = _run(tmp_path, f"pip_install_project_skip_pygobject log {args}")
assert result.returncode == 0, result.stderr
runtime, project = _calls(tmp_path)
assert runtime[runtime.index("-r") + 1].endswith("/requirements/runtime.txt")
assert "--require-hashes" in runtime
assert {"--no-deps", "--no-build-isolation"} <= set(project)
assert ("-e" in project) == editable
assert project[-1] == "project directory"
def test_failed_dependencies_never_install_project(tmp_path: Path) -> None:
result = _run(tmp_path, "pip_install_project_skip_pygobject log .", fail_pip=True)
assert result.returncode != 0
assert len(_calls(tmp_path)) == 1
@pytest.mark.parametrize("kind", ["missing", "empty", "unknown-extra"])
def test_missing_pins_fail_before_pip(tmp_path: Path, kind: str) -> None:
path = tmp_path / "missing.txt"
if kind == "empty":
path.touch()
command = (
"pip_install_extras_skip_pygobject log typo"
if kind == "unknown-extra"
else f"pip_install_reqs_file log {shlex.quote(str(path))}"
)
result = _run(tmp_path, command)
assert result.returncode != 0
assert not _calls(tmp_path)
@pytest.mark.parametrize("backend", ["cpu", "vulkan", "cuda"])
def test_rebuild_uses_only_locked_pywhispercpp(tmp_path: Path, backend: str) -> None:
command = (
"install_cpu_pywhispercpp log"
if backend == "cpu"
else f"GGML_{backend.upper()}=1 pip_reinstall_pywhispercpp log --no-binary pywhispercpp"
)
result = _run(tmp_path, command)
assert result.returncode == 0, result.stderr
(call,) = _calls(tmp_path)
assert {"--require-hashes", "--no-deps", "--no-build-isolation", "--force-reinstall"} <= set(
call
)
selected = (tmp_path / "pywhispercpp.txt").read_text()
assert re.findall(r"^([\w.-]+)==", selected, re.M) == ["pywhispercpp"]
lock = tomllib.loads((ROOT / "uv.lock").read_text())
package = next(p for p in lock["package"] if p["name"] == "pywhispercpp")
assert f"pywhispercpp=={package['version']}" in selected
for artifact in [package["sdist"], *package["wheels"]]:
assert artifact["hash"] in selected
def test_bootstrap_uses_only_hashed_wheels(tmp_path: Path) -> None:
result = _run(tmp_path, "install_pinned_build_tools")
assert result.returncode == 0, result.stderr
(call,) = _calls(tmp_path)
assert {"--require-hashes", "--only-binary=:all:", "--ignore-installed", "--no-deps"} <= set(
call
)
@pytest.mark.parametrize("kind", ["missing", "empty"])
def test_bootstrap_rejects_missing_or_empty_export(tmp_path: Path, kind: str) -> None:
"""Reject missing pins before invoking pip, including in a conditional."""
requirements = tmp_path / "requirements"
requirements.mkdir()
export = requirements / "installer-build.txt"
if kind == "empty":
export.touch()
result = _run(
tmp_path,
f"INSTALL_DIR={shlex.quote(str(tmp_path))}\n" "install_pinned_build_tools || exit 23",
)
assert result.returncode == 23, result.stdout + result.stderr
assert f"Missing or empty pinned requirements: {export}" in result.stderr
assert not _calls(tmp_path)
@pytest.mark.parametrize("remote_aware", [False, True])
def test_remote_handoff_preserves_tagged_behavior(tmp_path: Path, remote_aware: bool) -> None:
"""A main bootstrap must preserve remote behavior for every tag."""
clone = tmp_path / "old tagged tree"
clone.mkdir()
marker = 'CLEANUP_ON_EXIT="${VOCALINUX_REMOTE_INSTALL:-no}"\n' if remote_aware else ""
(clone / "install.sh").write_text(
"#!/bin/bash\n"
+ marker
+ 'printf "%s\\n" "${VOCALINUX_REMOTE_INSTALL:-no}" "$PWD" "$@"\n'
+ "helper=activate-vocalinux.sh\n"
+ 'if [ "${VOCALINUX_REMOTE_INSTALL:-no}" = yes ]; then\n'
+ ' mkdir -p "$HOME/.local/bin"\n'
+ ' helper="$HOME/.local/bin/activate-vocalinux.sh"\n'
+ "fi\n"
+ 'printf helper > "$helper"\n'
)
scratch = tmp_path / "scratch"
scratch.mkdir()
text = INSTALLER.read_text()
start = text.index("handoff_to_tagged_installer() {")
end = text.index("\n}", start) + 2
handoff = text[start:end]
home = tmp_path / "home"
home.mkdir()
result = subprocess.run(
[
"bash",
"-c",
f"set -eu\n{handoff}\ncd {shlex.quote(str(clone))}\n"
f"INSTALL_DIR={shlex.quote(str(clone))}\n"
f"VOCALINUX_TMP_DIR={shlex.quote(str(scratch))}\n"
"INSTALLER_ARGS=(--auto --tag=v0.17.0 --engine=remote_api)\n"
'print_error() { echo "$*" >&2; }\n'
"handoff_to_tagged_installer",
],
env={**os.environ, "HOME": str(home)},
capture_output=True,
text=True,
timeout=10,
)
assert result.returncode == 0, result.stderr
assert result.stdout.splitlines() == [
"yes" if remote_aware else "no",
str(clone),
"--auto",
"--tag=v0.17.0",
"--engine=remote_api",
f"--venv-dir={home}/.local/share/vocalinux/venv",
]
assert scratch.exists() != remote_aware
helper = home / ".local/bin/activate-vocalinux.sh"
assert helper.read_text() == "helper"
assert not (clone / "activate-vocalinux.sh").exists()
def test_every_pip_install_has_an_explicit_resolution_boundary() -> None:
"""Catch a new engine adding a bare pip install outside the shared helpers."""
source = INSTALLER.read_text().replace("\\\n", " ")
installs = [
line.strip()
for line in source.splitlines()
if re.match(r'^\s*(?:pip |"\$VENV_DIR/bin/python" -m pip )install ', line)
]
assert len(installs) >= 4
for line in installs:
assert "--no-deps" in line, line
if "--require-hashes" in line:
assert "--no-build-isolation" in line or "--only-binary=:all:" in line, line
else:
assert '--log "$pip_log" "$@"' in line, line # the local project only
assert "--no-build-isolation" in line, line
def test_selector_preserves_python_markers_and_rejects_absent_package(tmp_path: Path) -> None:
spec = importlib.util.spec_from_file_location("installer_requirements", SELECTOR)
assert spec and spec.loader
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
source = ROOT / "requirements/runtime.txt"
selected = module.select_requirements(source, "numpy")
assert "python_full_version < '3.12'" in selected
assert "python_full_version >= '3.12'" in selected
assert selected.count("numpy==") == 2
with pytest.raises(ValueError, match="No pin"):
module.select_requirements(source, "typo")
@pytest.mark.parametrize("minor", [11, 12, 13, 14])
def test_whisper_does_not_replace_runtime_or_build_pins(minor: int) -> None:
environment = {
"python_version": f"3.{minor}",
"python_full_version": f"3.{minor}.0",
"sys_platform": "linux",
"platform_machine": "x86_64",
}
def pins(name: str) -> dict[str, str]:
result = {}
for line in (ROOT / f"requirements/{name}.txt").read_text().splitlines():
if re.match(r"^[\w.-]+==", line):
requirement = Requirement(line.rstrip(" \\"))
if requirement.marker is None or requirement.marker.evaluate(environment):
result[requirement.name] = str(requirement.specifier)
return result
base = pins("runtime") | pins("installer-build")
whisper = pins("whisper")
assert whisper["torch"].endswith("+cpu")
for name in base.keys() & whisper.keys():
assert base[name] == whisper[name], name
@pytest.mark.timeout(60)
@pytest.mark.parametrize("tamper", [False, True])
def test_real_pip_checks_hash_before_install(tmp_path: Path, tamper: bool) -> None:
"""Use a local wheel and no index: exercise pip, not a mocked hash checker."""
venv = tmp_path / "venv"
subprocess.run([sys.executable, "-m", "venv", "--system-site-packages", str(venv)], check=True)
wheel = tmp_path / "pinned_fixture-1.0-py3-none-any.whl"
with zipfile.ZipFile(wheel, "w") as archive:
archive.writestr("pinned_fixture.py", "VALUE = 1\n")
archive.writestr(
"pinned_fixture-1.0.dist-info/METADATA",
"Metadata-Version: 2.1\nName: pinned-fixture\nVersion: 1.0\n",
)
archive.writestr(
"pinned_fixture-1.0.dist-info/WHEEL",
"Wheel-Version: 1.0\nGenerator: test\nRoot-Is-Purelib: true\nTag: py3-none-any\n",
)
archive.writestr("pinned_fixture-1.0.dist-info/RECORD", "")
digest = hashlib.sha256(wheel.read_bytes()).hexdigest()
if tamper:
with zipfile.ZipFile(wheel, "a") as archive:
archive.writestr("tampered.txt", "changed bytes")
requirements = tmp_path / "requirements.txt"
requirements.write_text(f"pinned-fixture==1.0 --hash=sha256:{digest}\n")
source = (
f"source <(sed -n '/^pip_install_reqs_file() {{$/,/^}}$/p' {shlex.quote(str(INSTALLER))})"
)
result = subprocess.run(
[
"bash",
"-c",
f'{source}\nVENV_DIR={shlex.quote(str(venv))}\nprint_error() {{ echo "$*" >&2; }}\npip_install_reqs_file {shlex.quote(str(tmp_path / "pip.log"))} {shlex.quote(str(requirements))}',
],
env={
**os.environ,
"PIP_NO_INDEX": "1",
"PIP_FIND_LINKS": str(tmp_path),
"PIP_DISABLE_PIP_VERSION_CHECK": "1",
},
capture_output=True,
text=True,
timeout=30,
)
assert (result.returncode != 0) == tamper, result.stdout + result.stderr
if tamper:
assert "HASHES" in result.stderr
def test_source_built_runtime_packages_have_build_deps_on_split_devel_distros() -> None:
"""The pinned runtime builds these from source; distro lists that split
-devel packages must carry their build deps."""
runtime = (ROOT / "requirements/runtime.txt").read_text(encoding="utf-8")
installer = INSTALLER.read_text(encoding="utf-8")
def package_line(prefix: str) -> str:
return next(line for line in installer.splitlines() if f"local {prefix}=" in line)
build_deps = {
"pycairo": ("cairo-devel", "libcairo2-dev"),
"pyaudio": ("portaudio-devel", "portaudio19-dev"),
"evdev": ("python3-devel", "python3-dev"),
}
for name, (dnf_pkg, apt_pkg) in build_deps.items():
if not re.search(rf"^{name}==", runtime, re.MULTILINE):
continue # wheels-only or dropped: nothing to build
assert dnf_pkg in package_line("DNF_PACKAGES"), name
assert apt_pkg in package_line("APT_PACKAGES_UBUNTU"), name
assert apt_pkg in package_line("APT_PACKAGES_DEBIAN_BASE"), name
+3 -46
View File
@@ -2,8 +2,6 @@
import os
import subprocess
import sys
import tomllib
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[1]
@@ -64,9 +62,8 @@ def test_system_dep_and_venv_failures_use_structured_exit_codes() -> None:
in source
)
assert 'exit "$EXIT_MISSING_DEPS"' in source
assert (
'print_error "Failed to update pip, setuptools, and wheel"; exit "$EXIT_NETWORK"' in source
)
bootstrap_failure = source.split("install_pinned_build_tools || {", 1)[1].split("}", 1)[0]
assert 'exit "$EXIT_NETWORK"' in bootstrap_failure
assert (
'print_error "Failed to install Vocalinux package. Installation cannot continue."' in source
)
@@ -90,7 +87,7 @@ def test_whispercpp_fallback_installs_vosk_extra() -> None:
def test_project_pip_install_skips_pygobject() -> None:
source = _installer_source()
assert "write_pip_reqs_skip_pygobject()" in source
assert "write_pip_reqs_skip_pygobject()" not in source
assert "pip_install_project_skip_pygobject()" in source
assert "pip install --no-deps" in source
assert "--no-emit-package pygobject" in source
@@ -101,46 +98,6 @@ def test_project_pip_install_skips_pygobject() -> None:
assert 'pip install -e ".[whisper,dev]"' not in source
def _run_reqs_writer(dest: Path, *extras: str) -> None:
source = _installer_source()
start = source.index("from pathlib import Path\nimport re\nimport sys\n")
end = source.index("\nPY\n}", start)
result = subprocess.run(
[sys.executable, "-", str(dest), *extras],
check=False,
cwd=INSTALLER.parent,
input=source[start:end],
capture_output=True,
text=True,
)
assert result.returncode == 0, result.stderr
def test_write_pip_reqs_skip_pygobject_runtime(tmp_path) -> None:
dest = tmp_path / "runtime.txt"
_run_reqs_writer(dest)
reqs = dest.read_text().splitlines()
assert reqs
assert all("pygobject" not in req.lower() for req in reqs)
assert any(req.startswith("pyaudio") for req in reqs)
assert any(req.startswith("pywhispercpp") for req in reqs)
def test_write_pip_reqs_skip_pygobject_vosk_extra(tmp_path) -> None:
"""The writer copies an extra's specifiers through, bounds and all.
Read out of pyproject.toml rather than written here as a literal. This
assertion was `["vosk>=0.3.45"]` and failed the day the extra gained an
upper bound, reporting an intentional pyproject edit as an installer defect.
"""
with PYPROJECT.open("rb") as handle:
expected = tomllib.load(handle)["project"]["optional-dependencies"]["vosk"]
assert expected, "the vosk extra declares nothing; this would compare [] to []"
dest = tmp_path / "vosk.txt"
_run_reqs_writer(dest, "vosk")
assert dest.read_text().splitlines() == expected
def test_settings_uses_engine_flag_not_removed_with_whisper() -> None:
text = SETTINGS.read_text(encoding="utf-8")
assert "./install.sh --engine=whisper" in text
Generated
+243 -12
View File
@@ -2,9 +2,12 @@ version = 1
revision = 3
requires-python = ">=3.11"
resolution-markers = [
"python_full_version >= '3.15'",
"python_full_version >= '3.12' and python_full_version < '3.15'",
"python_full_version < '3.12'",
"python_full_version >= '3.15' and sys_platform != 'ios'",
"python_full_version >= '3.15' and sys_platform == 'ios'",
"python_full_version >= '3.12' and python_full_version < '3.15' and sys_platform != 'ios'",
"python_full_version >= '3.12' and python_full_version < '3.15' and sys_platform == 'ios'",
"python_full_version < '3.12' and sys_platform != 'ios'",
"python_full_version < '3.12' and sys_platform == 'ios'",
]
[[package]]
@@ -16,6 +19,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929, upload-time = "2024-07-26T18:15:02.05Z" },
]
[[package]]
name = "altgraph"
version = "0.17.5"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/7e/f8/97fdf103f38fed6792a1601dbc16cc8aac56e7459a9fff08c812d8ae177a/altgraph-0.17.5.tar.gz", hash = "sha256:c87b395dd12fabde9c99573a9749d67da8d29ef9de0125c7f536699b4a9bc9e7", size = 48428, upload-time = "2025-11-21T20:35:50.583Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a9/ba/000a1996d4308bc65120167c21241a3b205464a2e0b58deda26ae8ac21d1/altgraph-0.17.5-py2.py3-none-any.whl", hash = "sha256:f3a22400bce1b0c701683820ac4f3b159cd301acab067c51c653e06961600597", size = 21228, upload-time = "2025-11-21T20:35:49.444Z" },
]
[[package]]
name = "anyio"
version = "4.15.1"
@@ -440,6 +452,32 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl", hash = "sha256:e6f9f66136c816745b9d65817da91d61d957fb16e02e4dcd0552553c5a197b76", size = 119243, upload-time = "2026-06-24T17:45:13.73Z" },
]
[[package]]
name = "cmake"
version = "3.31.10"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/37/7b/fbadb3f4fe90ad6ef57f9f5f9e4f721af8e86376fbdf11da2c6ed099830e/cmake-3.31.10.tar.gz", hash = "sha256:ec3d14a0e72e401b3665034dc37901df17f0b4e9c5b163be6cfedfb93470ac0f", size = 34499, upload-time = "2025-11-20T17:07:54.664Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/99/3b/6ed408a99709808df4014bead522e075f0e8d1100e6d886eb5bc30fee04e/cmake-3.31.10-py3-none-macosx_10_10_universal2.whl", hash = "sha256:ad697643a00d9ba85179590a383c4f7401169b55ebf4b8b2938daf28c6bdeb6d", size = 48001731, upload-time = "2025-11-20T17:06:57.473Z" },
{ url = "https://files.pythonhosted.org/packages/ad/59/acc2f79180d8aaf55b707ee65b5296ae76a3295ebff9e65d840849b6abc0/cmake-3.31.10-py3-none-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:7c300e4ae68fbc1414a85505f7feb262cee82ff3304a286885ebf803b11a997c", size = 27579802, upload-time = "2025-11-20T17:07:00.676Z" },
{ url = "https://files.pythonhosted.org/packages/cc/0a/2f17b5cc0d3ac1ce2324364c044d170d06167f8d6b7464ee76857114d95e/cmake-3.31.10-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3c17bb24dba15f8ecc3fd706afe04264410ef88796f4115c119327c961d5dc57", size = 26832178, upload-time = "2025-11-20T17:07:03.475Z" },
{ url = "https://files.pythonhosted.org/packages/b1/6c/d629c3b6a30105f5946e754b42d6ce84be36c190cc70b70fb2eb8a0ffc37/cmake-3.31.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4a5615f31f692c9b9aa8b365704e4b76172348af6fa40e16fea3f118bb01194", size = 27165148, upload-time = "2025-11-20T17:07:06.895Z" },
{ url = "https://files.pythonhosted.org/packages/9b/d8/9842811ec5615598003499e2d38062d42651a20d022f93f9a590807d76b3/cmake-3.31.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d2ec5fc45d305227020c82213140a51a0cebe3c84f0299036f05716b3a52f60", size = 28889720, upload-time = "2025-11-20T17:07:09.597Z" },
{ url = "https://files.pythonhosted.org/packages/01/e9/7042b018121ceaae48416d37edb9924646e3cc8bbb417374cafdf8c2fa58/cmake-3.31.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7864605238759a4ae8e3bd1fda2bb03978e3e37df310852662dcf53866413c8", size = 30757069, upload-time = "2025-11-20T17:07:12.537Z" },
{ url = "https://files.pythonhosted.org/packages/24/a8/4e320cd6dfae630c5d9532d822c20a095565bcb159be839919ff7ea2952f/cmake-3.31.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1debc3a0823ce5d8d1bc17154599bbbb337c2681f93622b618bc78f46576e42a", size = 26932214, upload-time = "2025-11-20T17:07:16.075Z" },
{ url = "https://files.pythonhosted.org/packages/f4/2e/cefc60143950ca1a8dda26d4c8484e6fc406db16e7ca098ebae549de35f9/cmake-3.31.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f766bb46367e5e0559fa33184653754bce044583a06014dcaebf8e6dff8a1f1", size = 27808794, upload-time = "2025-11-20T17:07:18.974Z" },
{ url = "https://files.pythonhosted.org/packages/1f/55/3f7d68d03f116142ce1076d65898e3d31c24d72985e827bfd9c601c8bc65/cmake-3.31.10-py3-none-manylinux_2_31_armv7l.whl", hash = "sha256:91410816db3beefe2f6032d721f9978c98dc7646e9992c0325486597164fab81", size = 24986234, upload-time = "2025-11-20T17:07:21.596Z" },
{ url = "https://files.pythonhosted.org/packages/e1/2e/634e46413472be742f3f422f159c41079bdc8ffba67538228f94a166c9ee/cmake-3.31.10-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:c2e5361dea9754ed3b06cf834894fb47dcbe7036d5e5d87acaeb10ff3dd5fd10", size = 27849273, upload-time = "2025-11-20T17:07:24.369Z" },
{ url = "https://files.pythonhosted.org/packages/6f/af/fac7ee4d79b688b94b4f6a6e5c4b080dca7594342576ad88a52b02a2d4eb/cmake-3.31.10-py3-none-musllinux_1_1_i686.whl", hash = "sha256:6970bb75c4dfc28cc31ff0cd848194d09094ae00d605181e1345b2ff70b61050", size = 31391299, upload-time = "2025-11-20T17:07:27.228Z" },
{ url = "https://files.pythonhosted.org/packages/d4/14/62339280a675106227ff650166c2899fe9f822ef9b855365563e71115125/cmake-3.31.10-py3-none-musllinux_1_1_ppc64le.whl", hash = "sha256:4cefb0a28ac1268b4eed4b595bf3aaff8de9704089066027700ec36584eccab8", size = 32105563, upload-time = "2025-11-20T17:07:34.352Z" },
{ url = "https://files.pythonhosted.org/packages/ba/19/a3014beb02b344599e7a879f9c91d5e388aa76924b1369e13ffd535d613d/cmake-3.31.10-py3-none-musllinux_1_1_s390x.whl", hash = "sha256:b331984de38dbda22d676f8812c8905526341ba7b397fe8c359255ff4d051193", size = 27972718, upload-time = "2025-11-20T17:07:37.492Z" },
{ url = "https://files.pythonhosted.org/packages/b0/53/63b70d583c93352beeb692f0ec6bf4dede96f92df85c009577a663be304a/cmake-3.31.10-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:678fc23db37cc69f01e18eb28790450ecc9401fd2fcd43364cc18f92330c12c2", size = 29497491, upload-time = "2025-11-20T17:07:40.316Z" },
{ url = "https://files.pythonhosted.org/packages/fc/a3/9d3a3881e70b947abe2d779e4c37d1aa9ac7f8339354e78d6036d520a220/cmake-3.31.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e135d5f1e59f1dc1c80eea87321977d6c0eff86cb601c28e0965a1dd457ea587", size = 33183971, upload-time = "2025-11-20T17:07:43.392Z" },
{ url = "https://files.pythonhosted.org/packages/06/f2/8e13be79373ef808659e52680643e0388057060e2627757b90df72c50681/cmake-3.31.10-py3-none-win32.whl", hash = "sha256:b059a1810a2ce766b3e531bdc8d730bc192e260a9fa7dec7a0eb7a053d6063c7", size = 33416497, upload-time = "2025-11-20T17:07:46.467Z" },
{ url = "https://files.pythonhosted.org/packages/84/4b/e433ab430c580ec8e3d54cb2ec5c7ea76ae0b1e6ef2c2998c854f21d7780/cmake-3.31.10-py3-none-win_amd64.whl", hash = "sha256:f1ea1fe826355560e8976c3d5794d9357444209bc0e0d56676c71e6a571fd474", size = 36630429, upload-time = "2025-11-20T17:07:49.445Z" },
{ url = "https://files.pythonhosted.org/packages/9f/c3/4eb3288ccd779556fee4b7b0955bdb14545bbae83f85f7c819dde8013708/cmake-3.31.10-py3-none-win_arm64.whl", hash = "sha256:422a54711aa977af19d59b8f6010354cdda0b72a2e6d702b6d892e3e2cdf98a2", size = 35457178, upload-time = "2025-11-20T17:07:52.367Z" },
]
[[package]]
name = "colorama"
version = "0.4.6"
@@ -682,6 +720,18 @@ nvtx = [
{ name = "nvidia-nvtx", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
[[package]]
name = "delvewheel"
version = "1.13.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pefile" },
]
sdist = { url = "https://files.pythonhosted.org/packages/36/8d/ad1ecad995732a6c53086ce3bf20479d37a970acc80b7bdb4ab1eb156f2e/delvewheel-1.13.1.tar.gz", hash = "sha256:ae445f35f411c367f5b350431ac5f1435af8128bff31ccf34035a409704da8c6", size = 64796, upload-time = "2026-08-28T18:31:07.461Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ea/d0/fc48bf4c00b80c1ced5ce3740ea0c5d040758dafce385275e5de559375a4/delvewheel-1.13.1-py3-none-any.whl", hash = "sha256:1b3bc696193a57e322b8bfd644de240be6e003066aae44cc3d5aef8cbee22ca3", size = 60375, upload-time = "2026-08-28T18:31:06.18Z" },
]
[[package]]
name = "distlib"
version = "0.4.3"
@@ -1045,6 +1095,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/d8/c6/32d68bfbf1d0c36888530ef6fd72864861af23dc546302b41033471a8c3a/llvmlite-0.49.0-cp314-cp314t-win_amd64.whl", hash = "sha256:be637e465010bc9c50f070468f7f1cf5385e92fee364d192dd5e6cea790ecba9", size = 42986602, upload-time = "2026-08-11T16:25:57.69Z" },
]
[[package]]
name = "macholib"
version = "1.16.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "altgraph" },
]
sdist = { url = "https://files.pythonhosted.org/packages/10/2f/97589876ea967487978071c9042518d28b958d87b17dceb7cdc1d881f963/macholib-1.16.4.tar.gz", hash = "sha256:f408c93ab2e995cd2c46e34fe328b130404be143469e41bc366c807448979362", size = 59427, upload-time = "2025-11-22T08:28:38.373Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c7/d1/a9f36f8ecdf0fb7c9b1e78c8d7af12b8c8754e74851ac7b94a8305540fc7/macholib-1.16.4-py2.py3-none-any.whl", hash = "sha256:da1a3fa8266e30f0ce7e97c6a54eefaae8edd1e5f86f3eb8b95457cae90265ea", size = 38117, upload-time = "2025-11-22T08:28:36.939Z" },
]
[[package]]
name = "markupsafe"
version = "3.0.3"
@@ -1128,6 +1190,29 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350, upload-time = "2022-01-24T01:14:49.62Z" },
]
[[package]]
name = "meson"
version = "1.12.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/48/91/d58a3eb45ed54bf32b96806dd2f4efd407f7a9675953e15e8ef257840a0d/meson-1.12.0.tar.gz", hash = "sha256:88afe0c20e52030218924ac37d0c81c59b4b5f3ae3752c8c6d7470c7d365886c", size = 2518280, upload-time = "2026-08-10T22:10:27.439Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/07/68/b0117422eb0a46d9d8d9e328f0c5b5c835179bfc058688bca35c90c89eba/meson-1.12.0-py3-none-any.whl", hash = "sha256:71f133147fa0fcfe8f4df49fa1045771064947834538409e5d97b3613aac8b4e", size = 1106208, upload-time = "2026-08-10T22:10:23.093Z" },
]
[[package]]
name = "meson-python"
version = "0.21.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "meson" },
{ name = "packaging" },
{ name = "pyproject-metadata" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ed/f2/ab554fe4f020ec5f0ab4e4af04318e6ab99660f8d8d14e3d064db2b786a6/meson_python-0.21.1.tar.gz", hash = "sha256:78b3345dcbc0fed7b939e7e37a9faab35bddaae07bf62e7542c8ad479c395af5", size = 113878, upload-time = "2026-09-11T14:00:59.641Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/9e/4f/03aeed5a32e7e8158d8c617fe65b622410db974fe02e3bd78da9689a44fd/meson_python-0.21.1-py3-none-any.whl", hash = "sha256:270bc9b78957c47e0aa1758ad616dba3f943d8f9cbdb944d318c3c1c7a49e4bd", size = 29579, upload-time = "2026-09-11T14:00:58.133Z" },
]
[[package]]
name = "more-itertools"
version = "11.1.0"
@@ -1224,6 +1309,32 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" },
]
[[package]]
name = "ninja"
version = "1.13.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/43/73/79a0b22fc731989c708068427579e840a6cf4e937fe7ae5c5d0b7356ac22/ninja-1.13.0.tar.gz", hash = "sha256:4a40ce995ded54d9dc24f8ea37ff3bf62ad192b547f6c7126e7e25045e76f978", size = 242558, upload-time = "2025-08-11T15:10:19.421Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3c/74/d02409ed2aa865e051b7edda22ad416a39d81a84980f544f8de717cab133/ninja-1.13.0-py3-none-macosx_10_9_universal2.whl", hash = "sha256:fa2a8bfc62e31b08f83127d1613d10821775a0eb334197154c4d6067b7068ff1", size = 310125, upload-time = "2025-08-11T15:09:50.971Z" },
{ url = "https://files.pythonhosted.org/packages/8e/de/6e1cd6b84b412ac1ef327b76f0641aeb5dcc01e9d3f9eee0286d0c34fd93/ninja-1.13.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3d00c692fb717fd511abeb44b8c5d00340c36938c12d6538ba989fe764e79630", size = 177467, upload-time = "2025-08-11T15:09:52.767Z" },
{ url = "https://files.pythonhosted.org/packages/c8/83/49320fb6e58ae3c079381e333575fdbcf1cca3506ee160a2dcce775046fa/ninja-1.13.0-py3-none-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:be7f478ff9f96a128b599a964fc60a6a87b9fa332ee1bd44fa243ac88d50291c", size = 187834, upload-time = "2025-08-11T15:09:54.115Z" },
{ url = "https://files.pythonhosted.org/packages/56/c7/ba22748fb59f7f896b609cd3e568d28a0a367a6d953c24c461fe04fc4433/ninja-1.13.0-py3-none-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:60056592cf495e9a6a4bea3cd178903056ecb0943e4de45a2ea825edb6dc8d3e", size = 202736, upload-time = "2025-08-11T15:09:55.745Z" },
{ url = "https://files.pythonhosted.org/packages/79/22/d1de07632b78ac8e6b785f41fa9aad7a978ec8c0a1bf15772def36d77aac/ninja-1.13.0-py3-none-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:1c97223cdda0417f414bf864cfb73b72d8777e57ebb279c5f6de368de0062988", size = 179034, upload-time = "2025-08-11T15:09:57.394Z" },
{ url = "https://files.pythonhosted.org/packages/ed/de/0e6edf44d6a04dabd0318a519125ed0415ce437ad5a1ec9b9be03d9048cf/ninja-1.13.0-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fb46acf6b93b8dd0322adc3a4945452a4e774b75b91293bafcc7b7f8e6517dfa", size = 180716, upload-time = "2025-08-11T15:09:58.696Z" },
{ url = "https://files.pythonhosted.org/packages/54/28/938b562f9057aaa4d6bfbeaa05e81899a47aebb3ba6751e36c027a7f5ff7/ninja-1.13.0-py3-none-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4be9c1b082d244b1ad7ef41eb8ab088aae8c109a9f3f0b3e56a252d3e00f42c1", size = 146843, upload-time = "2025-08-11T15:10:00.046Z" },
{ url = "https://files.pythonhosted.org/packages/2a/fb/d06a3838de4f8ab866e44ee52a797b5491df823901c54943b2adb0389fbb/ninja-1.13.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:6739d3352073341ad284246f81339a384eec091d9851a886dfa5b00a6d48b3e2", size = 154402, upload-time = "2025-08-11T15:10:01.657Z" },
{ url = "https://files.pythonhosted.org/packages/31/bf/0d7808af695ceddc763cf251b84a9892cd7f51622dc8b4c89d5012779f06/ninja-1.13.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:11be2d22027bde06f14c343f01d31446747dbb51e72d00decca2eb99be911e2f", size = 552388, upload-time = "2025-08-11T15:10:03.349Z" },
{ url = "https://files.pythonhosted.org/packages/9d/70/c99d0c2c809f992752453cce312848abb3b1607e56d4cd1b6cded317351a/ninja-1.13.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:aa45b4037b313c2f698bc13306239b8b93b4680eb47e287773156ac9e9304714", size = 472501, upload-time = "2025-08-11T15:10:04.735Z" },
{ url = "https://files.pythonhosted.org/packages/9f/43/c217b1153f0e499652f5e0766da8523ce3480f0a951039c7af115e224d55/ninja-1.13.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5f8e1e8a1a30835eeb51db05cf5a67151ad37542f5a4af2a438e9490915e5b72", size = 638280, upload-time = "2025-08-11T15:10:06.512Z" },
{ url = "https://files.pythonhosted.org/packages/8c/45/9151bba2c8d0ae2b6260f71696330590de5850e5574b7b5694dce6023e20/ninja-1.13.0-py3-none-musllinux_1_2_ppc64le.whl", hash = "sha256:3d7d7779d12cb20c6d054c61b702139fd23a7a964ec8f2c823f1ab1b084150db", size = 642420, upload-time = "2025-08-11T15:10:08.35Z" },
{ url = "https://files.pythonhosted.org/packages/3c/fb/95752eb635bb8ad27d101d71bef15bc63049de23f299e312878fc21cb2da/ninja-1.13.0-py3-none-musllinux_1_2_riscv64.whl", hash = "sha256:d741a5e6754e0bda767e3274a0f0deeef4807f1fec6c0d7921a0244018926ae5", size = 585106, upload-time = "2025-08-11T15:10:09.818Z" },
{ url = "https://files.pythonhosted.org/packages/c1/31/aa56a1a286703800c0cbe39fb4e82811c277772dc8cd084f442dd8e2938a/ninja-1.13.0-py3-none-musllinux_1_2_s390x.whl", hash = "sha256:e8bad11f8a00b64137e9b315b137d8bb6cbf3086fbdc43bf1f90fd33324d2e96", size = 707138, upload-time = "2025-08-11T15:10:11.366Z" },
{ url = "https://files.pythonhosted.org/packages/34/6f/5f5a54a1041af945130abdb2b8529cbef0cdcbbf9bcf3f4195378319d29a/ninja-1.13.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b4f2a072db3c0f944c32793e91532d8948d20d9ab83da9c0c7c15b5768072200", size = 581758, upload-time = "2025-08-11T15:10:13.295Z" },
{ url = "https://files.pythonhosted.org/packages/95/97/51359c77527d45943fe7a94d00a3843b81162e6c4244b3579fe8fc54cb9c/ninja-1.13.0-py3-none-win32.whl", hash = "sha256:8cfbb80b4a53456ae8a39f90ae3d7a2129f45ea164f43fadfa15dc38c4aef1c9", size = 267201, upload-time = "2025-08-11T15:10:15.158Z" },
{ url = "https://files.pythonhosted.org/packages/29/45/c0adfbfb0b5895aa18cec400c535b4f7ff3e52536e0403602fc1a23f7de9/ninja-1.13.0-py3-none-win_amd64.whl", hash = "sha256:fb8ee8719f8af47fed145cced4a85f0755dd55d45b2bddaf7431fa89803c5f3e", size = 309975, upload-time = "2025-08-11T15:10:16.697Z" },
{ url = "https://files.pythonhosted.org/packages/df/93/a7b983643d1253bb223234b5b226e69de6cda02b76cdca7770f684b795f5/ninja-1.13.0-py3-none-win_arm64.whl", hash = "sha256:3c0b40b1f0bba764644385319028650087b4c1b18cdfa6f45cb39a3669b81aa9", size = 290806, upload-time = "2025-08-11T15:10:18.018Z" },
]
[[package]]
name = "nodeenv"
version = "1.10.0"
@@ -1272,7 +1383,8 @@ name = "numpy"
version = "2.4.6"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version < '3.12'",
"python_full_version < '3.12' and sys_platform != 'ios'",
"python_full_version < '3.12' and sys_platform == 'ios'",
]
sdist = { url = "https://files.pythonhosted.org/packages/d0/ad/fed0499ce6a338d2a03ebae59cd15093910c8875328855781952abf6c2fe/numpy-2.4.6.tar.gz", hash = "sha256:f3a3570c4a2a16746ac2c31a7c7c7b0c186b95ce902e33db6f28094ed7387dda", size = 20735807, upload-time = "2026-05-18T23:37:14.07Z" }
wheels = [
@@ -1354,8 +1466,10 @@ name = "numpy"
version = "2.5.2"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.15'",
"python_full_version >= '3.12' and python_full_version < '3.15'",
"python_full_version >= '3.15' and sys_platform != 'ios'",
"python_full_version >= '3.15' and sys_platform == 'ios'",
"python_full_version >= '3.12' and python_full_version < '3.15' and sys_platform != 'ios'",
"python_full_version >= '3.12' and python_full_version < '3.15' and sys_platform == 'ios'",
]
sdist = { url = "https://files.pythonhosted.org/packages/9a/80/db0b4559e57ec36362bedbb05530a87fafbcb6067708c946967a41d449e7/numpy-2.5.2.tar.gz", hash = "sha256:d482d171c406ae88c5b19cad3b6a1c4c5209f886ab74bc44c2c865c23f52d860", size = 20773161, upload-time = "2026-08-09T13:48:27.962Z" }
wheels = [
@@ -1650,6 +1764,24 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" },
]
[[package]]
name = "pefile"
version = "2024.8.26"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/03/4f/2750f7f6f025a1507cd3b7218691671eecfd0bbebebe8b39aa0fe1d360b8/pefile-2024.8.26.tar.gz", hash = "sha256:3ff6c5d8b43e8c37bb6e6dd5085658d658a7a0bdcd20b6a07b1fcfc1c4e9d632", size = 76008, upload-time = "2024-08-26T20:58:38.155Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/54/16/12b82f791c7f50ddec566873d5bdd245baa1491bac11d15ffb98aecc8f8b/pefile-2024.8.26-py3-none-any.whl", hash = "sha256:76f8b485dcd3b1bb8166f1128d395fa3d87af26360c2358fb75b80019b957c6f", size = 74766, upload-time = "2024-08-26T21:01:02.632Z" },
]
[[package]]
name = "pip"
version = "26.2.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ae/15/4500e320e6b101ec3b719ae85b697d9940b6cda672bc555bd6016fc60c6f/pip-26.2.1.tar.gz", hash = "sha256:f6ad667e89a1fe78046c8f13232b247200f5258d7828f3f7883d660878e0813f", size = 1848877, upload-time = "2026-08-04T22:51:14.148Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f3/6e/1736e5b4ae2b778ef2f81c47d797de9f891d4d8acb047a24ca37a60294dd/pip-26.2.1-py3-none-any.whl", hash = "sha256:71138adf1f4ca900cdb7d289c21b7494329f2332b6d85f0e1c42108c0384ed3e", size = 1816632, upload-time = "2026-08-04T22:51:12.472Z" },
]
[[package]]
name = "platformdirs"
version = "4.11.3"
@@ -1765,6 +1897,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" },
]
[[package]]
name = "pyelftools"
version = "0.33"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a3/11/767522582afab1b884d277de0e6e011640cb9d7292a38694b4b1a1df1ae8/pyelftools-0.33.tar.gz", hash = "sha256:660d82dcbeb8e83d1702bd97f223f761625da06111c0cc988eac6b8ab0c1b61f", size = 15068655, upload-time = "2026-05-29T12:56:22.553Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/46/2a/f9697576603dae937727827505a6126a066affb227034e77e6f9068910da/pyelftools-0.33-py3-none-any.whl", hash = "sha256:f215ad5f47d3f1373a21496a6c9e0707c622840d0622f23ff7ce08678b020036", size = 201178, upload-time = "2026-05-29T12:56:20.587Z" },
]
[[package]]
name = "pyflakes"
version = "3.4.0"
@@ -1906,6 +2047,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/aa/eb/5fb627c2457046883c6fd12d25c44db40c12bcde4622dc0f30851108e106/pyobjc_framework_quartz-12.2.2-cp315-cp315t-macosx_10_15_universal2.whl", hash = "sha256:8f58c589b5a76ba98f186b1f3b19fb1c8b730e82351f81fb62e6194f64a71622", size = 224767, upload-time = "2026-08-11T19:40:30.991Z" },
]
[[package]]
name = "pyproject-metadata"
version = "0.12.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "packaging" },
]
sdist = { url = "https://files.pythonhosted.org/packages/4f/76/1cae539918a7b1746d624c2f01560b793c22cd8c081157505bb9bbf0e34d/pyproject_metadata-0.12.1.tar.gz", hash = "sha256:8809a4df6fe08279b39a8890669506ed3158e0617855ac9aff098fcbe772ae4c", size = 48457, upload-time = "2026-07-04T02:19:32.029Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b9/8e/d883718e872abc214ba053f60f7e6edc2abd5ffbd1544beb01a9c92ddd3c/pyproject_metadata-0.12.1-py3-none-any.whl", hash = "sha256:f7162d580a96386a8eb096da06215f981f547d1490f03055ef99e323bc2da427", size = 23452, upload-time = "2026-07-04T02:19:30.657Z" },
]
[[package]]
name = "pytest"
version = "9.1.1"
@@ -2227,6 +2380,23 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/6f/b6/26e41975febae63b7a6e3e02f32cff6cff2e4f10d19c929082f56aebf7c6/regex-2026.7.19-cp314-cp314t-win_arm64.whl", hash = "sha256:9a15e785f244f3e07847b984ce8773fc3da10a9f3c131cc49a4c5b4d672b4547", size = 283451, upload-time = "2026-07-19T00:19:46.639Z" },
]
[[package]]
name = "repairwheel"
version = "0.7.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "delvewheel" },
{ name = "macholib" },
{ name = "packaging" },
{ name = "pefile" },
{ name = "pyelftools" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/fb/74/e4c2ed3d34cde8cf790f4f5d99fb7b06933864ca8b5b6eed1dd237c7b763/repairwheel-0.7.0.tar.gz", hash = "sha256:46083dad76e35595712ae593c1c9f112fb3f37a0e63268906e6de8182de55122", size = 286421, upload-time = "2026-08-29T04:07:10.422Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/14/12/bbc4f17fa2661e40342a1e36ad099f085bb83d6dbd025fb00c69e313182f/repairwheel-0.7.0-py3-none-any.whl", hash = "sha256:7fff43ed5abbf9710ef5ea6478c10cfd551aae043f445fd46307d4b602674ce0", size = 146908, upload-time = "2026-08-29T04:07:11.442Z" },
]
[[package]]
name = "requests"
version = "2.34.2"
@@ -2253,11 +2423,25 @@ wheels = [
[[package]]
name = "setuptools"
version = "84.0.0"
version = "81.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/6d/44/f5da03a8ef95d369145c5bb53050e7877c9f3d312e128605fd9504829143/setuptools-84.0.0.tar.gz", hash = "sha256:f4695c21257f0d9b537ec2692c941d02ee143b7cc1276941349a546573b2ef73", size = 1168449, upload-time = "2026-08-08T18:27:58.365Z" }
sdist = { url = "https://files.pythonhosted.org/packages/0d/1c/73e719955c59b8e424d015ab450f51c0af856ae46ea2da83eba51cc88de1/setuptools-81.0.0.tar.gz", hash = "sha256:487b53915f52501f0a79ccfd0c02c165ffe06631443a886740b91af4b7a5845a", size = 1198299, upload-time = "2026-02-06T21:10:39.601Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/95/9c/c510029fc6ef33a6275cd2c5d3cecd6613dfd6aa401d57c54f1c18852ccf/setuptools-84.0.0-py3-none-any.whl", hash = "sha256:51a52592b3b99e102b609654876bd65f19f999935166d1352678931132b0c670", size = 818216, upload-time = "2026-08-08T18:27:56.719Z" },
{ url = "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl", hash = "sha256:fdd925d5c5d9f62e4b74b30d6dd7828ce236fd6ed998a08d81de62ce5a6310d6", size = 1062021, upload-time = "2026-02-06T21:10:37.175Z" },
]
[[package]]
name = "setuptools-scm"
version = "10.2.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "packaging" },
{ name = "setuptools" },
{ name = "vcs-versioning" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3c/87/1ff7adcf6e03021ae58ce401565be3c9b8c739a44d14a8253d38b3754117/setuptools_scm-10.2.3.tar.gz", hash = "sha256:f179ed3e2a63cf5823e5ee9aa9ca08386219400443a0553224d72dde3f206b44", size = 67696, upload-time = "2026-09-03T13:03:29.565Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/4b/00/e9c0591b77186f6c1a8479500456ee72cd30730836c58b7a8a2654909c23/setuptools_scm-10.2.3-py3-none-any.whl", hash = "sha256:7fcf8ff55c95eb8b572a23c81495e5559b9b90f3e82fcf0952bb76c37de27a81", size = 29123, upload-time = "2026-09-03T13:03:28.346Z" },
]
[[package]]
@@ -2331,7 +2515,8 @@ name = "sphinx"
version = "9.0.4"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version < '3.12'",
"python_full_version < '3.12' and sys_platform != 'ios'",
"python_full_version < '3.12' and sys_platform == 'ios'",
]
dependencies = [
{ name = "alabaster" },
@@ -2362,8 +2547,10 @@ name = "sphinx"
version = "9.1.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.15'",
"python_full_version >= '3.12' and python_full_version < '3.15'",
"python_full_version >= '3.15' and sys_platform != 'ios'",
"python_full_version >= '3.15' and sys_platform == 'ios'",
"python_full_version >= '3.12' and python_full_version < '3.15' and sys_platform != 'ios'",
"python_full_version >= '3.12' and python_full_version < '3.15' and sys_platform == 'ios'",
]
dependencies = [
{ name = "alabaster" },
@@ -2752,6 +2939,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" },
]
[[package]]
name = "vcs-versioning"
version = "2.4.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "packaging" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3e/97/792a4ef20344f9af3e16098b58b45eb5d6202259b84fc80c43bc000a5e6c/vcs_versioning-2.4.1.tar.gz", hash = "sha256:d4575de3115ec9434393c87c80ffb0eb98a16056bfe2b11ce0f3a97aff67fe0a", size = 164222, upload-time = "2026-09-16T07:47:40.267Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d7/20/29378edc8d7d2ce41892adc1356f4c6c6ae03b945d04ca6ade61afa3d5dc/vcs_versioning-2.4.1-py3-none-any.whl", hash = "sha256:b7089ec9bef67b2cad82148366e8eac4d63173f440ec62628282b59eb96bbcb0", size = 122157, upload-time = "2026-09-16T07:47:38.811Z" },
]
[[package]]
name = "virtualenv"
version = "21.7.4"
@@ -2815,6 +3014,16 @@ whisper = [
]
[package.dev-dependencies]
installer-build = [
{ name = "cmake" },
{ name = "meson-python" },
{ name = "ninja" },
{ name = "pip" },
{ name = "repairwheel" },
{ name = "setuptools" },
{ name = "setuptools-scm" },
{ name = "wheel" },
]
lint = [
{ name = "black" },
{ name = "flake8" },
@@ -2850,6 +3059,16 @@ requires-dist = [
provides-extras = ["vosk", "whisper", "parakeet", "faster-whisper", "vad", "dev", "docs"]
[package.metadata.requires-dev]
installer-build = [
{ name = "cmake", specifier = "==3.31.10" },
{ name = "meson-python", specifier = ">=0.16" },
{ name = "ninja", specifier = "==1.13.0" },
{ name = "pip", specifier = ">=25.3,<27" },
{ name = "repairwheel" },
{ name = "setuptools", specifier = ">=77,<82" },
{ name = "setuptools-scm", specifier = ">=8" },
{ name = "wheel" },
]
lint = [
{ name = "black", specifier = ">=23.0.0" },
{ name = "flake8", specifier = ">=6.0.0" },
@@ -2988,3 +3207,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/bf/e3/91e297e41381d9131f3142a9c1a50389fd96b98125ce9b81526fa4e14b9f/websockets-17.0.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:afbce6e3f0fac32dc87c2a0d84869d1a706460d64f39f3889386413e6e4d3d26", size = 213434, upload-time = "2026-07-31T11:31:24.707Z" },
{ url = "https://files.pythonhosted.org/packages/09/ce/3929538b2b9918f5eee623fbf3346893973191f6df93f19bbda097bd7bb7/websockets-17.0.1-py3-none-any.whl", hash = "sha256:c6be9cba65c65cc76dfa3d4619e359ff02a4476c74e179b215236c11a0b32345", size = 206718, upload-time = "2026-07-31T11:31:26.037Z" },
]
[[package]]
name = "wheel"
version = "0.48.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "packaging" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d0/20/50ed6bdf27dec98b568a8ae25dc599f35baa3d9709f9e83fd1edb56b9a90/wheel-0.48.0.tar.gz", hash = "sha256:94800765601e9171bf5d58d066e640662842bcedcbab982b2c90787a2c987322", size = 66471, upload-time = "2026-08-11T22:02:27.327Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2e/29/69cfbb602cd91690c55d38ba9fe53e6a7e76a6fa647bf38f19c138d25449/wheel-0.48.0-py3-none-any.whl", hash = "sha256:3217dcc807155e45db462d7ef2431f5ddda0d7273b700d05a67b271ceb1287ab", size = 33320, upload-time = "2026-08-11T22:02:26.1Z" },
]