From aa82c851fa33810a6cdabe60247e06560aacec87 Mon Sep 17 00:00:00 2001 From: MrNaif2018 Date: Wed, 25 Dec 2024 00:20:39 +0300 Subject: [PATCH] Use uv for docker images --- .circleci/config.yml | 4 +- compose/Dockerfile-coin.template | 16 +- compose/backend.Dockerfile | 11 +- compose/bch.Dockerfile | 12 +- compose/bnb.Dockerfile | 12 +- compose/bsty.Dockerfile | 12 +- compose/btc.Dockerfile | 12 +- compose/eth.Dockerfile | 12 +- compose/grs.Dockerfile | 12 +- compose/ltc.Dockerfile | 12 +- compose/matic.Dockerfile | 12 +- compose/sbch.Dockerfile | 12 +- compose/scripts/install-backend-plugins.sh | 2 +- compose/trx.Dockerfile | 12 +- compose/xmr.Dockerfile | 12 +- compose/xrg.Dockerfile | 12 +- generator/Dockerfile | 6 +- pyproject.toml | 17 + pytest.ini | 6 - setup.cfg | 8 - uv.lock | 341 +++++++++++++++++++++ 21 files changed, 479 insertions(+), 76 deletions(-) delete mode 100644 pytest.ini delete mode 100644 setup.cfg create mode 100644 uv.lock diff --git a/.circleci/config.yml b/.circleci/config.yml index 2867f35..e8d88b5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -15,8 +15,8 @@ jobs: name: install dependencies command: | cd generator - pip install -r requirements.txt - pip install -r test-requirements.txt + curl -LsSf https://astral.sh/uv/install.sh | sh + uv sync --frozen --compile-bytecode - run: name: run tests diff --git a/compose/Dockerfile-coin.template b/compose/Dockerfile-coin.template index 8ccf728..60d52d3 100644 --- a/compose/Dockerfile-coin.template +++ b/compose/Dockerfile-coin.template @@ -1,9 +1,13 @@ FROM python:3.11-alpine AS base +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ ENV ELECTRUM_USER=electrum ENV ELECTRUM_HOME=/home/$ELECTRUM_USER ENV ELECTRUM_DIRECTORY=${ELECTRUM_HOME}/.{{ env.name }}{{ if env.custom == "false" and env.coin != "btc" then "-"+env.coin else "" end }} ENV IN_DOCKER=1 +ENV UV_COMPILE_BYTECODE=1 +ENV UV_NO_CACHE=1 +ENV UV_NO_SYNC=1 ENV {{ env.coin | ascii_upcase }}_HOST=0.0.0.0 LABEL org.bitcart.image={{ env.coin }}-daemon @@ -12,15 +16,14 @@ FROM base AS compile-image COPY bitcart $ELECTRUM_HOME/site {{ if env.bases == "btc" then ( -}} -RUN apk add python3-dev build-base libffi-dev{{ if env.coin == "ltc" then " openssl-dev" else . end }} && \ +RUN apk add git python3-dev build-base libffi-dev{{ if env.coin == "ltc" then " openssl-dev" else . end }} && \ {{ ) elif env.bases == "bch" then ( -}} -RUN apk add gcc python3-dev musl-dev automake autoconf libtool file git make libffi-dev openssl-dev rust cargo && \ +RUN apk add git gcc python3-dev musl-dev automake autoconf libtool file git make libffi-dev openssl-dev rust cargo && \ {{ ) else ( -}} -RUN apk add gcc python3-dev musl-dev automake autoconf libtool file git make libffi-dev && \ +RUN apk add git gcc python3-dev musl-dev automake autoconf libtool file git make libffi-dev && \ {{ ) end -}} cd $ELECTRUM_HOME/site && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/base.txt && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/daemons/{{ env.coin }}.txt + uv sync --frozen --no-dev --group {{ env.coin }} FROM base AS build-image @@ -33,10 +36,11 @@ RUN adduser -D $ELECTRUM_USER && \ apk add --no-cache libsecp256k1-dev git && \ apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main jemalloc -COPY --from=compile-image --chown=electrum /root/.local $ELECTRUM_HOME/.local +COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site/.venv $ELECTRUM_HOME/.venv COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site $ELECTRUM_HOME/site ENV PYTHONUNBUFFERED=1 PYTHONMALLOC=malloc LD_PRELOAD=libjemalloc.so.2 MALLOC_CONF=background_thread:true,max_background_threads:1,metadata_thp:auto,dirty_decay_ms:80000,muzzy_decay_ms:80000 +ENV PATH="$ELECTRUM_HOME/.venv/bin:$PATH" USER $ELECTRUM_USER WORKDIR $ELECTRUM_HOME/site diff --git a/compose/backend.Dockerfile b/compose/backend.Dockerfile index b31d17b..e44e027 100644 --- a/compose/backend.Dockerfile +++ b/compose/backend.Dockerfile @@ -3,11 +3,15 @@ FROM golang:1.23-alpine AS go-builder RUN CGO_ENABLED=0 go install -ldflags '-X main.Version=docker -X main.envFile=/app/conf/.env' github.com/bitcart/bitcart-cli@master FROM python:3.11-slim-bullseye +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ ARG TARGETPLATFORM ENV IN_DOCKER=1 ENV GOSU_VERSION=1.16 LABEL org.bitcart.image=backend +ENV UV_COMPILE_BYTECODE=1 +ENV UV_NO_CACHE=1 +ENV UV_NO_SYNC=1 COPY bitcart /app COPY scripts/docker-entrypoint.sh /usr/local/bin/ @@ -19,12 +23,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends iproute2 openss chmod +x /usr/local/bin/gosu && \ groupadd --gid 1000 electrum && \ useradd --uid 1000 --gid electrum --shell /bin/bash --create-home electrum && \ - pip install -r requirements/deterministic/web.txt && \ - pip install -r requirements/deterministic/production.txt && \ + uv sync --frozen --no-dev --group web --group production && \ apt-get purge -y build-essential python3-dev libffi-dev wget && \ apt-get autoremove -y && \ - rm -rf /var/lib/apt/lists/* && \ - rm -rf /root/.cache/pip + rm -rf /var/lib/apt/lists/* ENV PYTHONUNBUFFERED=1 PYTHONMALLOC=malloc LD_PRELOAD=libjemalloc.so.2 MALLOC_CONF=background_thread:true,max_background_threads:1,metadata_thp:auto,dirty_decay_ms:80000,muzzy_decay_ms:80000 +ENV PATH="/app/.venv/bin:$PATH" ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] CMD ["sh"] diff --git a/compose/bch.Dockerfile b/compose/bch.Dockerfile index 539002b..7745f14 100644 --- a/compose/bch.Dockerfile +++ b/compose/bch.Dockerfile @@ -5,11 +5,15 @@ # FROM python:3.11-alpine AS base +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ ENV ELECTRUM_USER=electrum ENV ELECTRUM_HOME=/home/$ELECTRUM_USER ENV ELECTRUM_DIRECTORY=${ELECTRUM_HOME}/.electron-cash ENV IN_DOCKER=1 +ENV UV_COMPILE_BYTECODE=1 +ENV UV_NO_CACHE=1 +ENV UV_NO_SYNC=1 ENV BCH_HOST=0.0.0.0 LABEL org.bitcart.image=bch-daemon @@ -17,10 +21,9 @@ FROM base AS compile-image COPY bitcart $ELECTRUM_HOME/site -RUN apk add gcc python3-dev musl-dev automake autoconf libtool file git make libffi-dev openssl-dev rust cargo && \ +RUN apk add git gcc python3-dev musl-dev automake autoconf libtool file git make libffi-dev openssl-dev rust cargo && \ cd $ELECTRUM_HOME/site && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/base.txt && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/daemons/bch.txt + uv sync --frozen --no-dev --group bch FROM base AS build-image @@ -33,10 +36,11 @@ RUN adduser -D $ELECTRUM_USER && \ apk add --no-cache libsecp256k1-dev git && \ apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main jemalloc -COPY --from=compile-image --chown=electrum /root/.local $ELECTRUM_HOME/.local +COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site/.venv $ELECTRUM_HOME/.venv COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site $ELECTRUM_HOME/site ENV PYTHONUNBUFFERED=1 PYTHONMALLOC=malloc LD_PRELOAD=libjemalloc.so.2 MALLOC_CONF=background_thread:true,max_background_threads:1,metadata_thp:auto,dirty_decay_ms:80000,muzzy_decay_ms:80000 +ENV PATH="$ELECTRUM_HOME/.venv/bin:$PATH" USER $ELECTRUM_USER WORKDIR $ELECTRUM_HOME/site diff --git a/compose/bnb.Dockerfile b/compose/bnb.Dockerfile index de5871e..b204813 100644 --- a/compose/bnb.Dockerfile +++ b/compose/bnb.Dockerfile @@ -5,11 +5,15 @@ # FROM python:3.11-alpine AS base +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ ENV ELECTRUM_USER=electrum ENV ELECTRUM_HOME=/home/$ELECTRUM_USER ENV ELECTRUM_DIRECTORY=${ELECTRUM_HOME}/.bitcart-bnb ENV IN_DOCKER=1 +ENV UV_COMPILE_BYTECODE=1 +ENV UV_NO_CACHE=1 +ENV UV_NO_SYNC=1 ENV BNB_HOST=0.0.0.0 LABEL org.bitcart.image=bnb-daemon @@ -17,10 +21,9 @@ FROM base AS compile-image COPY bitcart $ELECTRUM_HOME/site -RUN apk add gcc python3-dev musl-dev automake autoconf libtool file git make libffi-dev && \ +RUN apk add git gcc python3-dev musl-dev automake autoconf libtool file git make libffi-dev && \ cd $ELECTRUM_HOME/site && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/base.txt && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/daemons/bnb.txt + uv sync --frozen --no-dev --group bnb FROM base AS build-image @@ -33,10 +36,11 @@ RUN adduser -D $ELECTRUM_USER && \ apk add --no-cache libsecp256k1-dev git && \ apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main jemalloc -COPY --from=compile-image --chown=electrum /root/.local $ELECTRUM_HOME/.local +COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site/.venv $ELECTRUM_HOME/.venv COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site $ELECTRUM_HOME/site ENV PYTHONUNBUFFERED=1 PYTHONMALLOC=malloc LD_PRELOAD=libjemalloc.so.2 MALLOC_CONF=background_thread:true,max_background_threads:1,metadata_thp:auto,dirty_decay_ms:80000,muzzy_decay_ms:80000 +ENV PATH="$ELECTRUM_HOME/.venv/bin:$PATH" USER $ELECTRUM_USER WORKDIR $ELECTRUM_HOME/site diff --git a/compose/bsty.Dockerfile b/compose/bsty.Dockerfile index 0cebcbc..7fcf9b0 100644 --- a/compose/bsty.Dockerfile +++ b/compose/bsty.Dockerfile @@ -5,11 +5,15 @@ # FROM python:3.11-alpine AS base +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ ENV ELECTRUM_USER=electrum ENV ELECTRUM_HOME=/home/$ELECTRUM_USER ENV ELECTRUM_DIRECTORY=${ELECTRUM_HOME}/.electrum-bsty ENV IN_DOCKER=1 +ENV UV_COMPILE_BYTECODE=1 +ENV UV_NO_CACHE=1 +ENV UV_NO_SYNC=1 ENV BSTY_HOST=0.0.0.0 LABEL org.bitcart.image=bsty-daemon @@ -17,10 +21,9 @@ FROM base AS compile-image COPY bitcart $ELECTRUM_HOME/site -RUN apk add python3-dev build-base libffi-dev && \ +RUN apk add git python3-dev build-base libffi-dev && \ cd $ELECTRUM_HOME/site && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/base.txt && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/daemons/bsty.txt + uv sync --frozen --no-dev --group bsty FROM base AS build-image @@ -33,10 +36,11 @@ RUN adduser -D $ELECTRUM_USER && \ apk add --no-cache libsecp256k1-dev git && \ apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main jemalloc -COPY --from=compile-image --chown=electrum /root/.local $ELECTRUM_HOME/.local +COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site/.venv $ELECTRUM_HOME/.venv COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site $ELECTRUM_HOME/site ENV PYTHONUNBUFFERED=1 PYTHONMALLOC=malloc LD_PRELOAD=libjemalloc.so.2 MALLOC_CONF=background_thread:true,max_background_threads:1,metadata_thp:auto,dirty_decay_ms:80000,muzzy_decay_ms:80000 +ENV PATH="$ELECTRUM_HOME/.venv/bin:$PATH" USER $ELECTRUM_USER WORKDIR $ELECTRUM_HOME/site diff --git a/compose/btc.Dockerfile b/compose/btc.Dockerfile index bb1bc83..70aed17 100644 --- a/compose/btc.Dockerfile +++ b/compose/btc.Dockerfile @@ -5,11 +5,15 @@ # FROM python:3.11-alpine AS base +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ ENV ELECTRUM_USER=electrum ENV ELECTRUM_HOME=/home/$ELECTRUM_USER ENV ELECTRUM_DIRECTORY=${ELECTRUM_HOME}/.electrum ENV IN_DOCKER=1 +ENV UV_COMPILE_BYTECODE=1 +ENV UV_NO_CACHE=1 +ENV UV_NO_SYNC=1 ENV BTC_HOST=0.0.0.0 LABEL org.bitcart.image=btc-daemon @@ -17,10 +21,9 @@ FROM base AS compile-image COPY bitcart $ELECTRUM_HOME/site -RUN apk add python3-dev build-base libffi-dev && \ +RUN apk add git python3-dev build-base libffi-dev && \ cd $ELECTRUM_HOME/site && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/base.txt && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/daemons/btc.txt + uv sync --frozen --no-dev --group btc FROM base AS build-image @@ -33,10 +36,11 @@ RUN adduser -D $ELECTRUM_USER && \ apk add --no-cache libsecp256k1-dev git && \ apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main jemalloc -COPY --from=compile-image --chown=electrum /root/.local $ELECTRUM_HOME/.local +COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site/.venv $ELECTRUM_HOME/.venv COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site $ELECTRUM_HOME/site ENV PYTHONUNBUFFERED=1 PYTHONMALLOC=malloc LD_PRELOAD=libjemalloc.so.2 MALLOC_CONF=background_thread:true,max_background_threads:1,metadata_thp:auto,dirty_decay_ms:80000,muzzy_decay_ms:80000 +ENV PATH="$ELECTRUM_HOME/.venv/bin:$PATH" USER $ELECTRUM_USER WORKDIR $ELECTRUM_HOME/site diff --git a/compose/eth.Dockerfile b/compose/eth.Dockerfile index d3d8c60..8a36b82 100644 --- a/compose/eth.Dockerfile +++ b/compose/eth.Dockerfile @@ -5,11 +5,15 @@ # FROM python:3.11-alpine AS base +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ ENV ELECTRUM_USER=electrum ENV ELECTRUM_HOME=/home/$ELECTRUM_USER ENV ELECTRUM_DIRECTORY=${ELECTRUM_HOME}/.bitcart-eth ENV IN_DOCKER=1 +ENV UV_COMPILE_BYTECODE=1 +ENV UV_NO_CACHE=1 +ENV UV_NO_SYNC=1 ENV ETH_HOST=0.0.0.0 LABEL org.bitcart.image=eth-daemon @@ -17,10 +21,9 @@ FROM base AS compile-image COPY bitcart $ELECTRUM_HOME/site -RUN apk add gcc python3-dev musl-dev automake autoconf libtool file git make libffi-dev && \ +RUN apk add git gcc python3-dev musl-dev automake autoconf libtool file git make libffi-dev && \ cd $ELECTRUM_HOME/site && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/base.txt && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/daemons/eth.txt + uv sync --frozen --no-dev --group eth FROM base AS build-image @@ -33,10 +36,11 @@ RUN adduser -D $ELECTRUM_USER && \ apk add --no-cache libsecp256k1-dev git && \ apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main jemalloc -COPY --from=compile-image --chown=electrum /root/.local $ELECTRUM_HOME/.local +COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site/.venv $ELECTRUM_HOME/.venv COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site $ELECTRUM_HOME/site ENV PYTHONUNBUFFERED=1 PYTHONMALLOC=malloc LD_PRELOAD=libjemalloc.so.2 MALLOC_CONF=background_thread:true,max_background_threads:1,metadata_thp:auto,dirty_decay_ms:80000,muzzy_decay_ms:80000 +ENV PATH="$ELECTRUM_HOME/.venv/bin:$PATH" USER $ELECTRUM_USER WORKDIR $ELECTRUM_HOME/site diff --git a/compose/grs.Dockerfile b/compose/grs.Dockerfile index 4037fbe..576e305 100644 --- a/compose/grs.Dockerfile +++ b/compose/grs.Dockerfile @@ -5,11 +5,15 @@ # FROM python:3.11-alpine AS base +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ ENV ELECTRUM_USER=electrum ENV ELECTRUM_HOME=/home/$ELECTRUM_USER ENV ELECTRUM_DIRECTORY=${ELECTRUM_HOME}/.electrum-grs ENV IN_DOCKER=1 +ENV UV_COMPILE_BYTECODE=1 +ENV UV_NO_CACHE=1 +ENV UV_NO_SYNC=1 ENV GRS_HOST=0.0.0.0 LABEL org.bitcart.image=grs-daemon @@ -17,10 +21,9 @@ FROM base AS compile-image COPY bitcart $ELECTRUM_HOME/site -RUN apk add python3-dev build-base libffi-dev && \ +RUN apk add git python3-dev build-base libffi-dev && \ cd $ELECTRUM_HOME/site && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/base.txt && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/daemons/grs.txt + uv sync --frozen --no-dev --group grs FROM base AS build-image @@ -33,10 +36,11 @@ RUN adduser -D $ELECTRUM_USER && \ apk add --no-cache libsecp256k1-dev git && \ apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main jemalloc -COPY --from=compile-image --chown=electrum /root/.local $ELECTRUM_HOME/.local +COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site/.venv $ELECTRUM_HOME/.venv COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site $ELECTRUM_HOME/site ENV PYTHONUNBUFFERED=1 PYTHONMALLOC=malloc LD_PRELOAD=libjemalloc.so.2 MALLOC_CONF=background_thread:true,max_background_threads:1,metadata_thp:auto,dirty_decay_ms:80000,muzzy_decay_ms:80000 +ENV PATH="$ELECTRUM_HOME/.venv/bin:$PATH" USER $ELECTRUM_USER WORKDIR $ELECTRUM_HOME/site diff --git a/compose/ltc.Dockerfile b/compose/ltc.Dockerfile index 4b71151..b9be249 100644 --- a/compose/ltc.Dockerfile +++ b/compose/ltc.Dockerfile @@ -5,11 +5,15 @@ # FROM python:3.11-alpine AS base +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ ENV ELECTRUM_USER=electrum ENV ELECTRUM_HOME=/home/$ELECTRUM_USER ENV ELECTRUM_DIRECTORY=${ELECTRUM_HOME}/.electrum-ltc ENV IN_DOCKER=1 +ENV UV_COMPILE_BYTECODE=1 +ENV UV_NO_CACHE=1 +ENV UV_NO_SYNC=1 ENV LTC_HOST=0.0.0.0 LABEL org.bitcart.image=ltc-daemon @@ -17,10 +21,9 @@ FROM base AS compile-image COPY bitcart $ELECTRUM_HOME/site -RUN apk add python3-dev build-base libffi-dev openssl-dev && \ +RUN apk add git python3-dev build-base libffi-dev openssl-dev && \ cd $ELECTRUM_HOME/site && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/base.txt && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/daemons/ltc.txt + uv sync --frozen --no-dev --group ltc FROM base AS build-image @@ -33,10 +36,11 @@ RUN adduser -D $ELECTRUM_USER && \ apk add --no-cache libsecp256k1-dev git && \ apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main jemalloc -COPY --from=compile-image --chown=electrum /root/.local $ELECTRUM_HOME/.local +COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site/.venv $ELECTRUM_HOME/.venv COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site $ELECTRUM_HOME/site ENV PYTHONUNBUFFERED=1 PYTHONMALLOC=malloc LD_PRELOAD=libjemalloc.so.2 MALLOC_CONF=background_thread:true,max_background_threads:1,metadata_thp:auto,dirty_decay_ms:80000,muzzy_decay_ms:80000 +ENV PATH="$ELECTRUM_HOME/.venv/bin:$PATH" USER $ELECTRUM_USER WORKDIR $ELECTRUM_HOME/site diff --git a/compose/matic.Dockerfile b/compose/matic.Dockerfile index 5cb1b9e..8d866e8 100644 --- a/compose/matic.Dockerfile +++ b/compose/matic.Dockerfile @@ -5,11 +5,15 @@ # FROM python:3.11-alpine AS base +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ ENV ELECTRUM_USER=electrum ENV ELECTRUM_HOME=/home/$ELECTRUM_USER ENV ELECTRUM_DIRECTORY=${ELECTRUM_HOME}/.bitcart-matic ENV IN_DOCKER=1 +ENV UV_COMPILE_BYTECODE=1 +ENV UV_NO_CACHE=1 +ENV UV_NO_SYNC=1 ENV MATIC_HOST=0.0.0.0 LABEL org.bitcart.image=matic-daemon @@ -17,10 +21,9 @@ FROM base AS compile-image COPY bitcart $ELECTRUM_HOME/site -RUN apk add gcc python3-dev musl-dev automake autoconf libtool file git make libffi-dev && \ +RUN apk add git gcc python3-dev musl-dev automake autoconf libtool file git make libffi-dev && \ cd $ELECTRUM_HOME/site && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/base.txt && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/daemons/matic.txt + uv sync --frozen --no-dev --group matic FROM base AS build-image @@ -33,10 +36,11 @@ RUN adduser -D $ELECTRUM_USER && \ apk add --no-cache libsecp256k1-dev git && \ apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main jemalloc -COPY --from=compile-image --chown=electrum /root/.local $ELECTRUM_HOME/.local +COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site/.venv $ELECTRUM_HOME/.venv COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site $ELECTRUM_HOME/site ENV PYTHONUNBUFFERED=1 PYTHONMALLOC=malloc LD_PRELOAD=libjemalloc.so.2 MALLOC_CONF=background_thread:true,max_background_threads:1,metadata_thp:auto,dirty_decay_ms:80000,muzzy_decay_ms:80000 +ENV PATH="$ELECTRUM_HOME/.venv/bin:$PATH" USER $ELECTRUM_USER WORKDIR $ELECTRUM_HOME/site diff --git a/compose/sbch.Dockerfile b/compose/sbch.Dockerfile index e3003c8..9d4f2d1 100644 --- a/compose/sbch.Dockerfile +++ b/compose/sbch.Dockerfile @@ -5,11 +5,15 @@ # FROM python:3.11-alpine AS base +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ ENV ELECTRUM_USER=electrum ENV ELECTRUM_HOME=/home/$ELECTRUM_USER ENV ELECTRUM_DIRECTORY=${ELECTRUM_HOME}/.bitcart-sbch ENV IN_DOCKER=1 +ENV UV_COMPILE_BYTECODE=1 +ENV UV_NO_CACHE=1 +ENV UV_NO_SYNC=1 ENV SBCH_HOST=0.0.0.0 LABEL org.bitcart.image=sbch-daemon @@ -17,10 +21,9 @@ FROM base AS compile-image COPY bitcart $ELECTRUM_HOME/site -RUN apk add gcc python3-dev musl-dev automake autoconf libtool file git make libffi-dev && \ +RUN apk add git gcc python3-dev musl-dev automake autoconf libtool file git make libffi-dev && \ cd $ELECTRUM_HOME/site && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/base.txt && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/daemons/sbch.txt + uv sync --frozen --no-dev --group sbch FROM base AS build-image @@ -33,10 +36,11 @@ RUN adduser -D $ELECTRUM_USER && \ apk add --no-cache libsecp256k1-dev git && \ apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main jemalloc -COPY --from=compile-image --chown=electrum /root/.local $ELECTRUM_HOME/.local +COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site/.venv $ELECTRUM_HOME/.venv COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site $ELECTRUM_HOME/site ENV PYTHONUNBUFFERED=1 PYTHONMALLOC=malloc LD_PRELOAD=libjemalloc.so.2 MALLOC_CONF=background_thread:true,max_background_threads:1,metadata_thp:auto,dirty_decay_ms:80000,muzzy_decay_ms:80000 +ENV PATH="$ELECTRUM_HOME/.venv/bin:$PATH" USER $ELECTRUM_USER WORKDIR $ELECTRUM_HOME/site diff --git a/compose/scripts/install-backend-plugins.sh b/compose/scripts/install-backend-plugins.sh index 64f421c..c455506 100755 --- a/compose/scripts/install-backend-plugins.sh +++ b/compose/scripts/install-backend-plugins.sh @@ -5,7 +5,7 @@ for org in modules/*; do echo "Installing $plugin" # check if file exists first if [ -f "$plugin/requirements.txt" ]; then - pip install -r "$plugin/requirements.txt" + uv pip install -r "$plugin/requirements.txt" fi # apply all patches from patches dir if [[ -d "$plugin/patches" ]]; then diff --git a/compose/trx.Dockerfile b/compose/trx.Dockerfile index 954f417..5b3ddf6 100644 --- a/compose/trx.Dockerfile +++ b/compose/trx.Dockerfile @@ -5,11 +5,15 @@ # FROM python:3.11-alpine AS base +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ ENV ELECTRUM_USER=electrum ENV ELECTRUM_HOME=/home/$ELECTRUM_USER ENV ELECTRUM_DIRECTORY=${ELECTRUM_HOME}/.bitcart-trx ENV IN_DOCKER=1 +ENV UV_COMPILE_BYTECODE=1 +ENV UV_NO_CACHE=1 +ENV UV_NO_SYNC=1 ENV TRX_HOST=0.0.0.0 LABEL org.bitcart.image=trx-daemon @@ -17,10 +21,9 @@ FROM base AS compile-image COPY bitcart $ELECTRUM_HOME/site -RUN apk add gcc python3-dev musl-dev automake autoconf libtool file git make libffi-dev && \ +RUN apk add git gcc python3-dev musl-dev automake autoconf libtool file git make libffi-dev && \ cd $ELECTRUM_HOME/site && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/base.txt && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/daemons/trx.txt + uv sync --frozen --no-dev --group trx FROM base AS build-image @@ -33,10 +36,11 @@ RUN adduser -D $ELECTRUM_USER && \ apk add --no-cache libsecp256k1-dev git && \ apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main jemalloc -COPY --from=compile-image --chown=electrum /root/.local $ELECTRUM_HOME/.local +COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site/.venv $ELECTRUM_HOME/.venv COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site $ELECTRUM_HOME/site ENV PYTHONUNBUFFERED=1 PYTHONMALLOC=malloc LD_PRELOAD=libjemalloc.so.2 MALLOC_CONF=background_thread:true,max_background_threads:1,metadata_thp:auto,dirty_decay_ms:80000,muzzy_decay_ms:80000 +ENV PATH="$ELECTRUM_HOME/.venv/bin:$PATH" USER $ELECTRUM_USER WORKDIR $ELECTRUM_HOME/site diff --git a/compose/xmr.Dockerfile b/compose/xmr.Dockerfile index 6f57194..9754c6e 100644 --- a/compose/xmr.Dockerfile +++ b/compose/xmr.Dockerfile @@ -5,11 +5,15 @@ # FROM python:3.11-alpine AS base +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ ENV ELECTRUM_USER=electrum ENV ELECTRUM_HOME=/home/$ELECTRUM_USER ENV ELECTRUM_DIRECTORY=${ELECTRUM_HOME}/.bitcart-xmr ENV IN_DOCKER=1 +ENV UV_COMPILE_BYTECODE=1 +ENV UV_NO_CACHE=1 +ENV UV_NO_SYNC=1 ENV XMR_HOST=0.0.0.0 LABEL org.bitcart.image=xmr-daemon @@ -17,10 +21,9 @@ FROM base AS compile-image COPY bitcart $ELECTRUM_HOME/site -RUN apk add gcc python3-dev musl-dev automake autoconf libtool file git make libffi-dev && \ +RUN apk add git gcc python3-dev musl-dev automake autoconf libtool file git make libffi-dev && \ cd $ELECTRUM_HOME/site && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/base.txt && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/daemons/xmr.txt + uv sync --frozen --no-dev --group xmr FROM base AS build-image @@ -33,10 +36,11 @@ RUN adduser -D $ELECTRUM_USER && \ apk add --no-cache libsecp256k1-dev git && \ apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main jemalloc -COPY --from=compile-image --chown=electrum /root/.local $ELECTRUM_HOME/.local +COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site/.venv $ELECTRUM_HOME/.venv COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site $ELECTRUM_HOME/site ENV PYTHONUNBUFFERED=1 PYTHONMALLOC=malloc LD_PRELOAD=libjemalloc.so.2 MALLOC_CONF=background_thread:true,max_background_threads:1,metadata_thp:auto,dirty_decay_ms:80000,muzzy_decay_ms:80000 +ENV PATH="$ELECTRUM_HOME/.venv/bin:$PATH" USER $ELECTRUM_USER WORKDIR $ELECTRUM_HOME/site diff --git a/compose/xrg.Dockerfile b/compose/xrg.Dockerfile index bcf163c..0947994 100644 --- a/compose/xrg.Dockerfile +++ b/compose/xrg.Dockerfile @@ -5,11 +5,15 @@ # FROM python:3.11-alpine AS base +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ ENV ELECTRUM_USER=electrum ENV ELECTRUM_HOME=/home/$ELECTRUM_USER ENV ELECTRUM_DIRECTORY=${ELECTRUM_HOME}/.oregano ENV IN_DOCKER=1 +ENV UV_COMPILE_BYTECODE=1 +ENV UV_NO_CACHE=1 +ENV UV_NO_SYNC=1 ENV XRG_HOST=0.0.0.0 LABEL org.bitcart.image=xrg-daemon @@ -17,10 +21,9 @@ FROM base AS compile-image COPY bitcart $ELECTRUM_HOME/site -RUN apk add gcc python3-dev musl-dev automake autoconf libtool file git make libffi-dev openssl-dev rust cargo && \ +RUN apk add git gcc python3-dev musl-dev automake autoconf libtool file git make libffi-dev openssl-dev rust cargo && \ cd $ELECTRUM_HOME/site && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/base.txt && \ - pip3 install --no-warn-script-location --user -r requirements/deterministic/daemons/xrg.txt + uv sync --frozen --no-dev --group xrg FROM base AS build-image @@ -33,10 +36,11 @@ RUN adduser -D $ELECTRUM_USER && \ apk add --no-cache libsecp256k1-dev git && \ apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main jemalloc -COPY --from=compile-image --chown=electrum /root/.local $ELECTRUM_HOME/.local +COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site/.venv $ELECTRUM_HOME/.venv COPY --from=compile-image --chown=electrum $ELECTRUM_HOME/site $ELECTRUM_HOME/site ENV PYTHONUNBUFFERED=1 PYTHONMALLOC=malloc LD_PRELOAD=libjemalloc.so.2 MALLOC_CONF=background_thread:true,max_background_threads:1,metadata_thp:auto,dirty_decay_ms:80000,muzzy_decay_ms:80000 +ENV PATH="$ELECTRUM_HOME/.venv/bin:$PATH" USER $ELECTRUM_USER WORKDIR $ELECTRUM_HOME/site diff --git a/generator/Dockerfile b/generator/Dockerfile index 1673ed6..d644228 100644 --- a/generator/Dockerfile +++ b/generator/Dockerfile @@ -1,6 +1,10 @@ FROM python:3.11-alpine +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ LABEL org.bitcart.image=docker-compose-generator COPY . /app/generator WORKDIR /app -RUN pip3 install --no-cache-dir -r generator/requirements.txt +ENV UV_COMPILE_BYTECODE=1 +ENV UV_NO_CACHE=1 +ENV UV_NO_SYNC=1 +RUN uv sync --frozen --no-dev ENTRYPOINT [ "python3", "-m", "generator"] diff --git a/pyproject.toml b/pyproject.toml index 5594413..44a29b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,13 @@ +[project] +name = "bitcart-compose-generator" +version = "1.0.0" +description = "Generate docker compose files based on env variables" +requires-python = ">=3.11" +dependencies = ["oyaml"] + +[dependency-groups] +dev = ["pre-commit", "pytest", "pytest-cov", "ruff"] + [tool.ruff] target-version = "py311" line-length = 127 @@ -24,3 +34,10 @@ mccabe = { max-complexity = 12 } [tool.ruff.lint.per-file-ignores] "generator/tests/*" = ["S"] + +[tool.pytest.ini_options] +addopts = ["--cov=.", "--cov-report", "term-missing"] +filterwarnings = [ + "error::DeprecationWarning", + "error::PendingDeprecationWarning", +] diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index 1f2f7a6..0000000 --- a/pytest.ini +++ /dev/null @@ -1,6 +0,0 @@ -[pytest] -python_files = tests.py test_*.py *_tests.py -addopts = --cov=. --cov-report term-missing -filterwarnings = - error::DeprecationWarning - error::PendingDeprecationWarning diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 82d1f1c..0000000 --- a/setup.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[flake8] -max-complexity=12 -max-line-length=127 -ignore=E266, E203, W503 - -[isort] -profile=black -line_length = 127 diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..f00a2a3 --- /dev/null +++ b/uv.lock @@ -0,0 +1,341 @@ +version = 1 +requires-python = ">=3.11" + +[[package]] +name = "bitcart-compose-generator" +version = "1.0.0" +source = { virtual = "." } +dependencies = [ + { name = "oyaml" }, +] + +[package.dev-dependencies] +dev = [ + { name = "pre-commit" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [{ name = "oyaml" }] + +[package.metadata.requires-dev] +dev = [ + { name = "pre-commit" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "ruff" }, +] + +[[package]] +name = "cfgv" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249 }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, +] + +[[package]] +name = "coverage" +version = "7.6.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/d2/c25011f4d036cf7e8acbbee07a8e09e9018390aee25ba085596c4b83d510/coverage-7.6.9.tar.gz", hash = "sha256:4a8d8977b0c6ef5aeadcb644da9e69ae0dcfe66ec7f368c89c72e058bd71164d", size = 801710 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/91/b3dc2f7f38b5cca1236ab6bbb03e84046dd887707b4ec1db2baa47493b3b/coverage-7.6.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:932fc826442132dde42ee52cf66d941f581c685a6313feebed358411238f60f9", size = 207133 }, + { url = "https://files.pythonhosted.org/packages/0d/2b/53fd6cb34d443429a92b3ec737f4953627e38b3bee2a67a3c03425ba8573/coverage-7.6.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:085161be5f3b30fd9b3e7b9a8c301f935c8313dcf928a07b116324abea2c1c2c", size = 207577 }, + { url = "https://files.pythonhosted.org/packages/74/f2/68edb1e6826f980a124f21ea5be0d324180bf11de6fd1defcf9604f76df0/coverage-7.6.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccc660a77e1c2bf24ddbce969af9447a9474790160cfb23de6be4fa88e3951c7", size = 239524 }, + { url = "https://files.pythonhosted.org/packages/d3/83/8fec0ee68c2c4a5ab5f0f8527277f84ed6f2bd1310ae8a19d0c5532253ab/coverage-7.6.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c69e42c892c018cd3c8d90da61d845f50a8243062b19d228189b0224150018a9", size = 236925 }, + { url = "https://files.pythonhosted.org/packages/8b/20/8f50e7c7ad271144afbc2c1c6ec5541a8c81773f59352f8db544cad1a0ec/coverage-7.6.9-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0824a28ec542a0be22f60c6ac36d679e0e262e5353203bea81d44ee81fe9c6d4", size = 238792 }, + { url = "https://files.pythonhosted.org/packages/6f/62/4ac2e5ad9e7a5c9ec351f38947528e11541f1f00e8a0cdce56f1ba7ae301/coverage-7.6.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4401ae5fc52ad8d26d2a5d8a7428b0f0c72431683f8e63e42e70606374c311a1", size = 237682 }, + { url = "https://files.pythonhosted.org/packages/58/2f/9d2203f012f3b0533c73336c74134b608742be1ce475a5c72012573cfbb4/coverage-7.6.9-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:98caba4476a6c8d59ec1eb00c7dd862ba9beca34085642d46ed503cc2d440d4b", size = 236310 }, + { url = "https://files.pythonhosted.org/packages/33/6d/31f6ab0b4f0f781636075f757eb02141ea1b34466d9d1526dbc586ed7078/coverage-7.6.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ee5defd1733fd6ec08b168bd4f5387d5b322f45ca9e0e6c817ea6c4cd36313e3", size = 237096 }, + { url = "https://files.pythonhosted.org/packages/7d/fb/e14c38adebbda9ed8b5f7f8e03340ac05d68d27b24397f8d47478927a333/coverage-7.6.9-cp311-cp311-win32.whl", hash = "sha256:f2d1ec60d6d256bdf298cb86b78dd715980828f50c46701abc3b0a2b3f8a0dc0", size = 209682 }, + { url = "https://files.pythonhosted.org/packages/a4/11/a782af39b019066af83fdc0e8825faaccbe9d7b19a803ddb753114b429cc/coverage-7.6.9-cp311-cp311-win_amd64.whl", hash = "sha256:0d59fd927b1f04de57a2ba0137166d31c1a6dd9e764ad4af552912d70428c92b", size = 210542 }, + { url = "https://files.pythonhosted.org/packages/60/52/b16af8989a2daf0f80a88522bd8e8eed90b5fcbdecf02a6888f3e80f6ba7/coverage-7.6.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:99e266ae0b5d15f1ca8d278a668df6f51cc4b854513daab5cae695ed7b721cf8", size = 207325 }, + { url = "https://files.pythonhosted.org/packages/0f/79/6b7826fca8846c1216a113227b9f114ac3e6eacf168b4adcad0cb974aaca/coverage-7.6.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9901d36492009a0a9b94b20e52ebfc8453bf49bb2b27bca2c9706f8b4f5a554a", size = 207563 }, + { url = "https://files.pythonhosted.org/packages/a7/07/0bc73da0ccaf45d0d64ef86d33b7d7fdeef84b4c44bf6b85fb12c215c5a6/coverage-7.6.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abd3e72dd5b97e3af4246cdada7738ef0e608168de952b837b8dd7e90341f015", size = 240580 }, + { url = "https://files.pythonhosted.org/packages/71/8a/9761f409910961647d892454687cedbaccb99aae828f49486734a82ede6e/coverage-7.6.9-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff74026a461eb0660366fb01c650c1d00f833a086b336bdad7ab00cc952072b3", size = 237613 }, + { url = "https://files.pythonhosted.org/packages/8b/10/ee7d696a17ac94f32f2dbda1e17e730bf798ae9931aec1fc01c1944cd4de/coverage-7.6.9-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65dad5a248823a4996724a88eb51d4b31587aa7aa428562dbe459c684e5787ae", size = 239684 }, + { url = "https://files.pythonhosted.org/packages/16/60/aa1066040d3c52fff051243c2d6ccda264da72dc6d199d047624d395b2b2/coverage-7.6.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:22be16571504c9ccea919fcedb459d5ab20d41172056206eb2994e2ff06118a4", size = 239112 }, + { url = "https://files.pythonhosted.org/packages/4e/e5/69f35344c6f932ba9028bf168d14a79fedb0dd4849b796d43c81ce75a3c9/coverage-7.6.9-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f957943bc718b87144ecaee70762bc2bc3f1a7a53c7b861103546d3a403f0a6", size = 237428 }, + { url = "https://files.pythonhosted.org/packages/32/20/adc895523c4a28f63441b8ac645abd74f9bdd499d2d175bef5b41fc7f92d/coverage-7.6.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ae1387db4aecb1f485fb70a6c0148c6cdaebb6038f1d40089b1fc84a5db556f", size = 239098 }, + { url = "https://files.pythonhosted.org/packages/a9/a6/e0e74230c9bb3549ec8ffc137cfd16ea5d56e993d6bffed2218bff6187e3/coverage-7.6.9-cp312-cp312-win32.whl", hash = "sha256:1a330812d9cc7ac2182586f6d41b4d0fadf9be9049f350e0efb275c8ee8eb692", size = 209940 }, + { url = "https://files.pythonhosted.org/packages/3e/18/cb5b88349d4aa2f41ec78d65f92ea32572b30b3f55bc2b70e87578b8f434/coverage-7.6.9-cp312-cp312-win_amd64.whl", hash = "sha256:b12c6b18269ca471eedd41c1b6a1065b2f7827508edb9a7ed5555e9a56dcfc97", size = 210726 }, + { url = "https://files.pythonhosted.org/packages/35/26/9abab6539d2191dbda2ce8c97b67d74cbfc966cc5b25abb880ffc7c459bc/coverage-7.6.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:899b8cd4781c400454f2f64f7776a5d87bbd7b3e7f7bda0cb18f857bb1334664", size = 207356 }, + { url = "https://files.pythonhosted.org/packages/44/da/d49f19402240c93453f606e660a6676a2a1fbbaa6870cc23207790aa9697/coverage-7.6.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:61f70dc68bd36810972e55bbbe83674ea073dd1dcc121040a08cdf3416c5349c", size = 207614 }, + { url = "https://files.pythonhosted.org/packages/da/e6/93bb9bf85497816082ec8da6124c25efa2052bd4c887dd3b317b91990c9e/coverage-7.6.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a289d23d4c46f1a82d5db4abeb40b9b5be91731ee19a379d15790e53031c014", size = 240129 }, + { url = "https://files.pythonhosted.org/packages/df/65/6a824b9406fe066835c1274a9949e06f084d3e605eb1a602727a27ec2fe3/coverage-7.6.9-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e216d8044a356fc0337c7a2a0536d6de07888d7bcda76febcb8adc50bdbbd00", size = 237276 }, + { url = "https://files.pythonhosted.org/packages/9f/79/6c7a800913a9dd23ac8c8da133ebb556771a5a3d4df36b46767b1baffd35/coverage-7.6.9-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c026eb44f744acaa2bda7493dad903aa5bf5fc4f2554293a798d5606710055d", size = 239267 }, + { url = "https://files.pythonhosted.org/packages/57/e7/834d530293fdc8a63ba8ff70033d5182022e569eceb9aec7fc716b678a39/coverage-7.6.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e77363e8425325384f9d49272c54045bbed2f478e9dd698dbc65dbc37860eb0a", size = 238887 }, + { url = "https://files.pythonhosted.org/packages/15/05/ec9d6080852984f7163c96984444e7cd98b338fd045b191064f943ee1c08/coverage-7.6.9-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:777abfab476cf83b5177b84d7486497e034eb9eaea0d746ce0c1268c71652077", size = 236970 }, + { url = "https://files.pythonhosted.org/packages/0a/d8/775937670b93156aec29f694ce37f56214ed7597e1a75b4083ee4c32121c/coverage-7.6.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:447af20e25fdbe16f26e84eb714ba21d98868705cb138252d28bc400381f6ffb", size = 238831 }, + { url = "https://files.pythonhosted.org/packages/f4/58/88551cb7fdd5ec98cb6044e8814e38583436b14040a5ece15349c44c8f7c/coverage-7.6.9-cp313-cp313-win32.whl", hash = "sha256:d872ec5aeb086cbea771c573600d47944eea2dcba8be5f3ee649bfe3cb8dc9ba", size = 210000 }, + { url = "https://files.pythonhosted.org/packages/b7/12/cfbf49b95120872785ff8d56ab1c7fe3970a65e35010c311d7dd35c5fd00/coverage-7.6.9-cp313-cp313-win_amd64.whl", hash = "sha256:fd1213c86e48dfdc5a0cc676551db467495a95a662d2396ecd58e719191446e1", size = 210753 }, + { url = "https://files.pythonhosted.org/packages/7c/68/c1cb31445599b04bde21cbbaa6d21b47c5823cdfef99eae470dfce49c35a/coverage-7.6.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ba9e7484d286cd5a43744e5f47b0b3fb457865baf07bafc6bee91896364e1419", size = 208091 }, + { url = "https://files.pythonhosted.org/packages/11/73/84b02c6b19c4a11eb2d5b5eabe926fb26c21c080e0852f5e5a4f01165f9e/coverage-7.6.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e5ea1cf0872ee455c03e5674b5bca5e3e68e159379c1af0903e89f5eba9ccc3a", size = 208369 }, + { url = "https://files.pythonhosted.org/packages/de/e0/ae5d878b72ff26df2e994a5c5b1c1f6a7507d976b23beecb1ed4c85411ef/coverage-7.6.9-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d10e07aa2b91835d6abec555ec8b2733347956991901eea6ffac295f83a30e4", size = 251089 }, + { url = "https://files.pythonhosted.org/packages/ab/9c/0aaac011aef95a93ef3cb2fba3fde30bc7e68a6635199ed469b1f5ea355a/coverage-7.6.9-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:13a9e2d3ee855db3dd6ea1ba5203316a1b1fd8eaeffc37c5b54987e61e4194ae", size = 246806 }, + { url = "https://files.pythonhosted.org/packages/f8/19/4d5d3ae66938a7dcb2f58cef3fa5386f838f469575b0bb568c8cc9e3a33d/coverage-7.6.9-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c38bf15a40ccf5619fa2fe8f26106c7e8e080d7760aeccb3722664c8656b030", size = 249164 }, + { url = "https://files.pythonhosted.org/packages/b3/0b/4ee8a7821f682af9ad440ae3c1e379da89a998883271f088102d7ca2473d/coverage-7.6.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d5275455b3e4627c8e7154feaf7ee0743c2e7af82f6e3b561967b1cca755a0be", size = 248642 }, + { url = "https://files.pythonhosted.org/packages/8a/12/36ff1d52be18a16b4700f561852e7afd8df56363a5edcfb04cf26a0e19e0/coverage-7.6.9-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8f8770dfc6e2c6a2d4569f411015c8d751c980d17a14b0530da2d7f27ffdd88e", size = 246516 }, + { url = "https://files.pythonhosted.org/packages/43/d0/8e258f6c3a527c1655602f4f576215e055ac704de2d101710a71a2affac2/coverage-7.6.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8d2dfa71665a29b153a9681edb1c8d9c1ea50dfc2375fb4dac99ea7e21a0bcd9", size = 247783 }, + { url = "https://files.pythonhosted.org/packages/a9/0d/1e4a48d289429d38aae3babdfcadbf35ca36bdcf3efc8f09b550a845bdb5/coverage-7.6.9-cp313-cp313t-win32.whl", hash = "sha256:5e6b86b5847a016d0fbd31ffe1001b63355ed309651851295315031ea7eb5a9b", size = 210646 }, + { url = "https://files.pythonhosted.org/packages/26/74/b0729f196f328ac55e42b1e22ec2f16d8bcafe4b8158a26ec9f1cdd1d93e/coverage-7.6.9-cp313-cp313t-win_amd64.whl", hash = "sha256:97ddc94d46088304772d21b060041c97fc16bdda13c6c7f9d8fcd8d5ae0d8611", size = 211815 }, +] + +[package.optional-dependencies] +toml = [ + { name = "tomli", marker = "python_full_version <= '3.11'" }, +] + +[[package]] +name = "distlib" +version = "0.3.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0d/dd/1bec4c5ddb504ca60fc29472f3d27e8d4da1257a854e1d96742f15c1d02d/distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403", size = 613923 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/a1/cf2472db20f7ce4a6be1253a81cfdf85ad9c7885ffbed7047fb72c24cf87/distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", size = 468973 }, +] + +[[package]] +name = "filelock" +version = "3.16.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/db/3ef5bb276dae18d6ec2124224403d1d67bccdbefc17af4cc8f553e341ab1/filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435", size = 18037 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/f8/feced7779d755758a52d1f6635d990b8d98dc0a29fa568bbe0625f18fdf3/filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0", size = 16163 }, +] + +[[package]] +name = "identify" +version = "2.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1a/5f/05f0d167be94585d502b4adf8c7af31f1dc0b1c7e14f9938a88fdbbcf4a7/identify-2.6.3.tar.gz", hash = "sha256:62f5dae9b5fef52c84cc188514e9ea4f3f636b1d8799ab5ebc475471f9e47a02", size = 99179 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c9/f5/09644a3ad803fae9eca8efa17e1f2aef380c7f0b02f7ec4e8d446e51d64a/identify-2.6.3-py2.py3-none-any.whl", hash = "sha256:9edba65473324c2ea9684b1f944fe3191db3345e50b6d04571d10ed164f8d7bd", size = 99049 }, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, +] + +[[package]] +name = "nodeenv" +version = "1.9.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314 }, +] + +[[package]] +name = "oyaml" +version = "1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/00/71/c721b9a524f6fe6f73469c90ec44784f0b2b1b23c438da7cc7daac1ede76/oyaml-1.0.tar.gz", hash = "sha256:ed8fc096811f4763e1907dce29c35895d6d5936c4d0400fe843a91133d4744ed", size = 2914 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/37/aa/111610d8bf5b1bb7a295a048fc648cec346347a8b0be5881defd2d1b4a52/oyaml-1.0-py2.py3-none-any.whl", hash = "sha256:3a378747b7fb2425533d1ce41962d6921cda075d46bb480a158d45242d156323", size = 2992 }, +] + +[[package]] +name = "packaging" +version = "24.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, +] + +[[package]] +name = "platformdirs" +version = "4.3.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 }, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, +] + +[[package]] +name = "pre-commit" +version = "4.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2e/c8/e22c292035f1bac8b9f5237a2622305bc0304e776080b246f3df57c4ff9f/pre_commit-4.0.1.tar.gz", hash = "sha256:80905ac375958c0444c65e9cebebd948b3cdb518f335a091a670a89d652139d2", size = 191678 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/8f/496e10d51edd6671ebe0432e33ff800aa86775d2d147ce7d43389324a525/pre_commit-4.0.1-py2.py3-none-any.whl", hash = "sha256:efde913840816312445dc98787724647c65473daefe420785f885e8ed9a06878", size = 218713 }, +] + +[[package]] +name = "pytest" +version = "8.3.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083 }, +] + +[[package]] +name = "pytest-cov" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage", extra = ["toml"] }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949 }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612 }, + { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040 }, + { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829 }, + { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167 }, + { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952 }, + { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301 }, + { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638 }, + { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850 }, + { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980 }, + { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 }, + { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 }, + { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 }, + { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 }, + { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 }, + { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 }, + { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 }, + { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, + { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, + { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 }, + { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 }, + { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 }, + { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 }, + { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 }, + { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 }, + { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 }, + { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 }, + { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, +] + +[[package]] +name = "ruff" +version = "0.8.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/34/37/9c02181ef38d55b77d97c68b78e705fd14c0de0e5d085202bb2b52ce5be9/ruff-0.8.4.tar.gz", hash = "sha256:0d5f89f254836799af1615798caa5f80b7f935d7a670fad66c5007928e57ace8", size = 3402103 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/67/f480bf2f2723b2e49af38ed2be75ccdb2798fca7d56279b585c8f553aaab/ruff-0.8.4-py3-none-linux_armv6l.whl", hash = "sha256:58072f0c06080276804c6a4e21a9045a706584a958e644353603d36ca1eb8a60", size = 10546415 }, + { url = "https://files.pythonhosted.org/packages/eb/7a/5aba20312c73f1ce61814e520d1920edf68ca3b9c507bd84d8546a8ecaa8/ruff-0.8.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ffb60904651c00a1e0b8df594591770018a0f04587f7deeb3838344fe3adabac", size = 10346113 }, + { url = "https://files.pythonhosted.org/packages/76/f4/c41de22b3728486f0aa95383a44c42657b2db4062f3234ca36fc8cf52d8b/ruff-0.8.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6ddf5d654ac0d44389f6bf05cee4caeefc3132a64b58ea46738111d687352296", size = 9943564 }, + { url = "https://files.pythonhosted.org/packages/0e/f0/afa0d2191af495ac82d4cbbfd7a94e3df6f62a04ca412033e073b871fc6d/ruff-0.8.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e248b1f0fa2749edd3350a2a342b67b43a2627434c059a063418e3d375cfe643", size = 10805522 }, + { url = "https://files.pythonhosted.org/packages/12/57/5d1e9a0fd0c228e663894e8e3a8e7063e5ee90f8e8e60cf2085f362bfa1a/ruff-0.8.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bf197b98ed86e417412ee3b6c893f44c8864f816451441483253d5ff22c0e81e", size = 10306763 }, + { url = "https://files.pythonhosted.org/packages/04/df/f069fdb02e408be8aac6853583572a2873f87f866fe8515de65873caf6b8/ruff-0.8.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c41319b85faa3aadd4d30cb1cffdd9ac6b89704ff79f7664b853785b48eccdf3", size = 11359574 }, + { url = "https://files.pythonhosted.org/packages/d3/04/37c27494cd02e4a8315680debfc6dfabcb97e597c07cce0044db1f9dfbe2/ruff-0.8.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:9f8402b7c4f96463f135e936d9ab77b65711fcd5d72e5d67597b543bbb43cf3f", size = 12094851 }, + { url = "https://files.pythonhosted.org/packages/81/b1/c5d7fb68506cab9832d208d03ea4668da9a9887a4a392f4f328b1bf734ad/ruff-0.8.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4e56b3baa9c23d324ead112a4fdf20db9a3f8f29eeabff1355114dd96014604", size = 11655539 }, + { url = "https://files.pythonhosted.org/packages/ef/38/8f8f2c8898dc8a7a49bc340cf6f00226917f0f5cb489e37075bcb2ce3671/ruff-0.8.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:736272574e97157f7edbbb43b1d046125fce9e7d8d583d5d65d0c9bf2c15addf", size = 12912805 }, + { url = "https://files.pythonhosted.org/packages/06/dd/fa6660c279f4eb320788876d0cff4ea18d9af7d9ed7216d7bd66877468d0/ruff-0.8.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fe710ab6061592521f902fca7ebcb9fabd27bc7c57c764298b1c1f15fff720", size = 11205976 }, + { url = "https://files.pythonhosted.org/packages/a8/d7/de94cc89833b5de455750686c17c9e10f4e1ab7ccdc5521b8fe911d1477e/ruff-0.8.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:13e9ec6d6b55f6da412d59953d65d66e760d583dd3c1c72bf1f26435b5bfdbae", size = 10792039 }, + { url = "https://files.pythonhosted.org/packages/6d/15/3e4906559248bdbb74854af684314608297a05b996062c9d72e0ef7c7097/ruff-0.8.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:97d9aefef725348ad77d6db98b726cfdb075a40b936c7984088804dfd38268a7", size = 10400088 }, + { url = "https://files.pythonhosted.org/packages/a2/21/9ed4c0e8133cb4a87a18d470f534ad1a8a66d7bec493bcb8bda2d1a5d5be/ruff-0.8.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ab78e33325a6f5374e04c2ab924a3367d69a0da36f8c9cb6b894a62017506111", size = 10900814 }, + { url = "https://files.pythonhosted.org/packages/0d/5d/122a65a18955bd9da2616b69bc839351f8baf23b2805b543aa2f0aed72b5/ruff-0.8.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:8ef06f66f4a05c3ddbc9121a8b0cecccd92c5bf3dd43b5472ffe40b8ca10f0f8", size = 11268828 }, + { url = "https://files.pythonhosted.org/packages/43/a9/1676ee9106995381e3d34bccac5bb28df70194167337ed4854c20f27c7ba/ruff-0.8.4-py3-none-win32.whl", hash = "sha256:552fb6d861320958ca5e15f28b20a3d071aa83b93caee33a87b471f99a6c0835", size = 8805621 }, + { url = "https://files.pythonhosted.org/packages/10/98/ed6b56a30ee76771c193ff7ceeaf1d2acc98d33a1a27b8479cbdb5c17a23/ruff-0.8.4-py3-none-win_amd64.whl", hash = "sha256:f21a1143776f8656d7f364bd264a9d60f01b7f52243fbe90e7670c0dfe0cf65d", size = 9660086 }, + { url = "https://files.pythonhosted.org/packages/13/9f/026e18ca7d7766783d779dae5e9c656746c6ede36ef73c6d934aaf4a6dec/ruff-0.8.4-py3-none-win_arm64.whl", hash = "sha256:9183dd615d8df50defa8b1d9a074053891ba39025cf5ae88e8bcb52edcc4bf08", size = 9074500 }, +] + +[[package]] +name = "tomli" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077 }, + { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429 }, + { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067 }, + { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030 }, + { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898 }, + { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894 }, + { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319 }, + { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273 }, + { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310 }, + { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309 }, + { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762 }, + { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453 }, + { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486 }, + { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349 }, + { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159 }, + { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243 }, + { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645 }, + { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584 }, + { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875 }, + { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418 }, + { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708 }, + { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582 }, + { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543 }, + { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691 }, + { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170 }, + { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530 }, + { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666 }, + { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954 }, + { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724 }, + { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383 }, + { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 }, +] + +[[package]] +name = "virtualenv" +version = "20.28.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bf/75/53316a5a8050069228a2f6d11f32046cfa94fbb6cc3f08703f59b873de2e/virtualenv-20.28.0.tar.gz", hash = "sha256:2c9c3262bb8e7b87ea801d715fae4495e6032450c71d2309be9550e7364049aa", size = 7650368 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/f9/0919cf6f1432a8c4baa62511f8f8da8225432d22e83e3476f5be1a1edc6e/virtualenv-20.28.0-py3-none-any.whl", hash = "sha256:23eae1b4516ecd610481eda647f3a7c09aea295055337331bb4e6892ecce47b0", size = 4276702 }, +]