diff --git a/.changeset/README.md b/.changeset/README.md deleted file mode 100644 index e325fcc5..00000000 --- a/.changeset/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Changesets - -To add changeset run: - -```bash -npx changeset -``` - -in the root of the project. This will create a new changeset in the `.changeset` folder. \ No newline at end of file diff --git a/.changeset/config.json b/.changeset/config.json deleted file mode 100644 index b102a073..00000000 --- a/.changeset/config.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json", - "changelog": "@changesets/cli/changelog", - "commit": false, - "fixed": [], - "ignore": [], - "linked": [], - "access": "public", - "baseBranch": "main", - "updateInternalDependencies": "patch", - "privatePackages": { - "version": true, - "tag": true - } -} \ No newline at end of file diff --git a/.changeset/jupyter-unix-socket.md b/.changeset/jupyter-unix-socket.md deleted file mode 100644 index b5b2ed6c..00000000 --- a/.changeset/jupyter-unix-socket.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@e2b/code-interpreter-template': patch ---- - -Isolate Jupyter behind a private Unix socket (`/run/e2b-jupyter/server.sock`, mode `0600`) instead of TCP port 8888, so Jupyter's HTTP API, kernel WebSockets, and interrupts are no longer reachable over the sandbox network interface. diff --git a/.github/scripts/build_release_itinerary.cjs b/.github/scripts/build_release_itinerary.cjs deleted file mode 100644 index 85f9eff4..00000000 --- a/.github/scripts/build_release_itinerary.cjs +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env node - -// This script formats the JSON written by `changeset status --output=` -// as the package list that goes into the release's Slack notifications. - -const path = require('path') - -// Packages are listed in this order; anything not named here still shows up, -// under its workspace name, after the ones that are. -const labels = { - '@e2b/data-extractor': 'Charts (e2b-charts)', - '@e2b/code-interpreter-template': 'Sandbox template (code-interpreter)', -} - -const statusFile = process.argv[2] -if (!statusFile) { - console.error('Usage: build_release_itinerary.cjs ') - process.exit(1) -} - -const order = Object.keys(labels) -const rank = (release) => { - const index = order.indexOf(release.name) - return index === -1 ? order.length : index -} - -const { releases } = require(path.resolve(statusFile)) -const lines = [...releases] - .sort((a, b) => rank(a) - rank(b)) - .map( - (release) => - `• ${labels[release.name] ?? release.name} v${release.newVersion}` - ) - -process.stdout.write(lines.join('\n') || '• No packages were published') diff --git a/.github/scripts/is_release.sh b/.github/scripts/is_release.sh deleted file mode 100755 index 436d0f07..00000000 --- a/.github/scripts/is_release.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -# This script checks if the current commit contains changesets. - -set -eu - -CHANGES=$(node -e "require('@changesets/read').default(process.cwd()).then(result => console.log(!!result.length))") - -echo "${CHANGES}" diff --git a/.github/scripts/is_release_for_package.sh b/.github/scripts/is_release_for_package.sh deleted file mode 100755 index c8965efb..00000000 --- a/.github/scripts/is_release_for_package.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -# This script checks if the specified package has changesets in the current commit. - -set -eu - -if [ $# -lt 1 ]; then - echo "Error: Package name is required as the first argument." >&2 - exit 1 -fi - -PACKAGE_NAME=$1 -PACKAGE_CHANGES=$(node -e "require('@changesets/read').default(process.cwd()).then(result => console.log(result.flatMap(changeset => changeset.releases.flatMap(release => release.name)).includes('${PACKAGE_NAME}')))") - -echo "${PACKAGE_CHANGES}" diff --git a/.github/workflows/build_prod_template.yml b/.github/workflows/build_prod_template.yml deleted file mode 100644 index 20658ecc..00000000 --- a/.github/workflows/build_prod_template.yml +++ /dev/null @@ -1,113 +0,0 @@ -name: Build Prod Template - -on: - workflow_dispatch: - inputs: - target_environment: - description: Target environment - required: true - type: choice - default: foxtrot - options: - - foxtrot - - staging - - juliett - skip_cache: - description: Skip build cache - required: false - type: boolean - default: false - -concurrency: - group: Release-${{ github.ref }}-${{ inputs.target_environment }} - cancel-in-progress: false - -permissions: - contents: read - -jobs: - build-template: - name: Build E2B template - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - - name: Parse .tool-versions - uses: wistia/parse-tool-versions@32f568a4ffd4bfa7720ebf93f171597d1ebc979a # v2.1.1 - with: - filename: '.tool-versions' - uppercase: 'true' - prefix: 'tool_version_' - - - name: Install uv - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0 - with: - version: '${{ env.TOOL_VERSION_UV }}' - python-version: '${{ env.TOOL_VERSION_PYTHON }}' - activate-environment: true - - - name: Install development dependencies - working-directory: ./template - run: uv pip install -r requirements-dev.txt - - - name: Resolve target environment - env: - TARGET_ENVIRONMENT: ${{ inputs.target_environment }} - FOXTROT_DOMAIN: ${{ vars.E2B_DOMAIN }} - FOXTROT_API_KEY: ${{ secrets.E2B_PROD_API_KEY }} - STAGING_API_KEY: ${{ secrets.E2B_STAGING_API_KEY }} - JULIETT_API_KEY: ${{ secrets.E2B_JULIETT_API_KEY }} - run: | - set -eu - - case "$TARGET_ENVIRONMENT" in - foxtrot) - E2B_DOMAIN="$FOXTROT_DOMAIN" - E2B_API_KEY="$FOXTROT_API_KEY" - ;; - staging) - E2B_DOMAIN="e2b-staging.dev" - E2B_API_KEY="$STAGING_API_KEY" - ;; - juliett) - E2B_DOMAIN="e2b-juliett.dev" - E2B_API_KEY="$JULIETT_API_KEY" - ;; - *) - echo "Unknown target environment: $TARGET_ENVIRONMENT" >&2 - exit 1 - ;; - esac - - if [ -z "$E2B_DOMAIN" ]; then - echo "Missing E2B domain for target environment: $TARGET_ENVIRONMENT" >&2 - exit 1 - fi - - if [ -z "$E2B_API_KEY" ]; then - echo "Missing API key secret for target environment: $TARGET_ENVIRONMENT" >&2 - exit 1 - fi - - echo "::add-mask::$E2B_API_KEY" - - { - echo "E2B_DOMAIN=$E2B_DOMAIN" - echo "E2B_API_KEY=$E2B_API_KEY" - } >> "$GITHUB_ENV" - - { - echo "### Build target" - echo - echo "Target: $TARGET_ENVIRONMENT" - echo "Domain: $E2B_DOMAIN" - } >> "$GITHUB_STEP_SUMMARY" - - - name: Build E2B template - id: build-template - working-directory: ./template - run: | - python build_prod.py - env: - SKIP_CACHE: ${{ inputs.skip_cache }} diff --git a/.github/workflows/build_test_template.yml b/.github/workflows/build_test_template.yml deleted file mode 100644 index 8ff0bfa0..00000000 --- a/.github/workflows/build_test_template.yml +++ /dev/null @@ -1,70 +0,0 @@ -name: Build Template - -on: - workflow_call: - secrets: - E2B_API_KEY: - required: true - inputs: - E2B_DOMAIN: - required: false - type: string - outputs: - template_id: - description: "The ID of the built template" - value: ${{ jobs.build.outputs.template_id }} - -permissions: - contents: read - -jobs: - build: - name: Build E2B Template - runs-on: ubuntu-latest - outputs: - template_id: ${{ steps.build-template.outputs.template_id }} - steps: - - name: Checkout repository - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - - name: Parse .tool-versions - uses: wistia/parse-tool-versions@32f568a4ffd4bfa7720ebf93f171597d1ebc979a # v2.1.1 - with: - filename: '.tool-versions' - uppercase: 'true' - prefix: 'tool_version_' - - - name: Set package version - working-directory: ./template - run: | - VERSION=$(cat ../chart_data_extractor/pyproject.toml | grep version | cut -d '"' -f 2) - echo "Version: $VERSION" - sed -i "s/e2b_charts/e2b_charts==${VERSION}/g" requirements.txt - - - name: Install uv - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0 - with: - version: '${{ env.TOOL_VERSION_UV }}' - python-version: '${{ env.TOOL_VERSION_PYTHON }}' - activate-environment: true - - - name: Install development dependencies - working-directory: ./template - run: uv pip install -r requirements-dev.txt - - - name: Generate Template Name - id: generate-template-id - run: | - E2B_TESTS_TEMPLATE=e2b-code-interpreter-ci-$(uuidgen) - echo "Generated Template Name: $E2B_TESTS_TEMPLATE" - echo "template_name=$E2B_TESTS_TEMPLATE" >> $GITHUB_OUTPUT - - - name: Build E2B template - id: build-template - working-directory: ./template - run: | - python build_ci.py - env: - E2B_API_KEY: ${{ secrets.E2B_API_KEY }} - E2B_DOMAIN: ${{ inputs.E2B_DOMAIN }} - E2B_TESTS_TEMPLATE: ${{ steps.generate-template-id.outputs.template_name }} diff --git a/.github/workflows/charts_tests.yml b/.github/workflows/charts_tests.yml deleted file mode 100644 index 4d0d7993..00000000 --- a/.github/workflows/charts_tests.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Test Python SDK - -on: - workflow_call: - -permissions: - contents: read - -jobs: - publish: - defaults: - run: - working-directory: ./chart_data_extractor - name: Chart Data Extractor - Build and test - runs-on: ubuntu-22.04 - steps: - - name: Checkout repository - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - - name: Parse .tool-versions - uses: wistia/parse-tool-versions@32f568a4ffd4bfa7720ebf93f171597d1ebc979a # v2.1.1 - with: - filename: '.tool-versions' - uppercase: 'true' - prefix: 'tool_version_' - - - name: Install uv - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0 - with: - version: '${{ env.TOOL_VERSION_UV }}' - python-version: '${{ env.TOOL_VERSION_PYTHON }}' - enable-cache: true - - - name: Install dependencies - run: uv sync --locked - - - name: Test build - run: uv build - - - name: Run tests - run: uv run pytest --verbose -x diff --git a/.github/workflows/cleanup_build_template.yml b/.github/workflows/cleanup_build_template.yml deleted file mode 100644 index 329a1eda..00000000 --- a/.github/workflows/cleanup_build_template.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Cleanup Build Template - -on: - workflow_call: - secrets: - E2B_API_KEY: - required: true - inputs: - E2B_DOMAIN: - required: false - type: string - E2B_TESTS_TEMPLATE: - required: true - type: string - -permissions: - contents: read - -jobs: - cleanup: - name: Cleanup Build Template - runs-on: ubuntu-latest - steps: - - name: Install E2B CLI - run: npm install -g @e2b/cli - - - name: Cleanup E2B template - id: cleanup-template - run: | - e2b template delete -y "${{ inputs.E2B_TESTS_TEMPLATE }}" - env: - E2B_API_KEY: ${{ secrets.E2B_API_KEY }} - E2B_DOMAIN: ${{ inputs.E2B_DOMAIN }} diff --git a/.github/workflows/code_interpreter_tests.yml b/.github/workflows/code_interpreter_tests.yml deleted file mode 100644 index c84deb8d..00000000 --- a/.github/workflows/code_interpreter_tests.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: Test Code Interpreter - -on: - workflow_call: - inputs: - E2B_DOMAIN: - required: false - type: string - default: '' - E2B_TESTS_TEMPLATE: - required: true - type: string - run_recovery_tests: - required: false - type: boolean - default: true - secrets: - E2B_API_KEY: - required: true - -permissions: - contents: read - -jobs: - test: - defaults: - run: - working-directory: ./tests - shell: bash - name: Code Interpreter - HTTP tests - runs-on: ubuntu-22.04 - steps: - - name: Checkout repository - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - - name: Parse .tool-versions - uses: wistia/parse-tool-versions@32f568a4ffd4bfa7720ebf93f171597d1ebc979a # v2.1.1 - with: - filename: '.tool-versions' - uppercase: 'true' - prefix: 'tool_version_' - - - name: Install uv - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0 - with: - version: '${{ env.TOOL_VERSION_UV }}' - python-version: '${{ env.TOOL_VERSION_PYTHON }}' - enable-cache: true - - - name: Install dependencies - run: uv sync --locked - - - name: Run tests - run: | - if [[ "${{ inputs.run_recovery_tests }}" == "true" ]]; then - uv run pytest --verbose --numprocesses=1 - else - uv run pytest --verbose --numprocesses=1 \ - --ignore=test_interrupt.py \ - --ignore=test_systemd.py \ - --deselect=test_async.py::test_async_interrupt - fi - env: - E2B_API_KEY: ${{ secrets.E2B_API_KEY }} - E2B_DOMAIN: ${{ inputs.E2B_DOMAIN }} - E2B_TESTS_TEMPLATE: ${{ inputs.E2B_TESTS_TEMPLATE }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index 42e84c5c..00000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: Lint - -on: - pull_request: - -permissions: - contents: read - -jobs: - lint: - name: Lint - runs-on: ubuntu-latest - - steps: - - name: Checkout Repo - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - - name: Parse .tool-versions - uses: wistia/parse-tool-versions@32f568a4ffd4bfa7720ebf93f171597d1ebc979a # v2.1.1 - with: - filename: '.tool-versions' - uppercase: 'true' - prefix: 'tool_version_' - - - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 - with: - version: ${{ env.TOOL_VERSION_PNPM }} - - - name: Setup Node.js 20 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version: '${{ env.TOOL_VERSION_NODE }}' - cache: pnpm - - - name: Configure pnpm - run: | - pnpm config set auto-install-peers true - pnpm config set exclude-links-from-lockfile true - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Install uv - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0 - with: - version: '${{ env.TOOL_VERSION_UV }}' - python-version: '${{ env.TOOL_VERSION_PYTHON }}' - enable-cache: true - - - name: Install Python dependencies - run: | - (cd chart_data_extractor && uv sync --locked) - (cd tests && uv sync --locked) - uv tool install ruff==0.11.12 - - - name: Run linting - run: | - pnpm run lint - - - name: Run formatting - run: | - pnpm run format - - - name: Check for uncommitted changes - run: | - if [[ -n $(git status --porcelain) ]]; then - echo "❌ Files are not formatted properly:" - git status --short - git diff - exit 1 - else - echo "✅ No changes detected." - fi \ No newline at end of file diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml deleted file mode 100644 index c38ba959..00000000 --- a/.github/workflows/pull_request.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Pull Request - -permissions: - contents: read - id-token: write - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -on: - pull_request: - branches: - - main - -jobs: - build-template: - uses: ./.github/workflows/build_test_template.yml - secrets: - E2B_API_KEY: ${{ secrets.E2B_API_KEY }} - with: - E2B_DOMAIN: ${{ vars.E2B_DOMAIN }} - code-interpreter-tests: - uses: ./.github/workflows/code_interpreter_tests.yml - needs: [build-template] - secrets: - E2B_API_KEY: ${{ secrets.E2B_API_KEY }} - with: - E2B_DOMAIN: ${{ vars.E2B_DOMAIN }} - E2B_TESTS_TEMPLATE: ${{ needs.build-template.outputs.template_id }} - cleanup-build-template: - uses: ./.github/workflows/cleanup_build_template.yml - needs: [build-template, code-interpreter-tests] - if: always() && !contains(needs.build-template.result, 'failure') && !contains(needs.build-template.result, 'cancelled') - secrets: - E2B_API_KEY: ${{ secrets.E2B_API_KEY }} - with: - E2B_DOMAIN: ${{ vars.E2B_DOMAIN }} - E2B_TESTS_TEMPLATE: ${{ needs.build-template.outputs.template_id }} - charts-tests: - uses: ./.github/workflows/charts_tests.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 5db139bd..00000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,431 +0,0 @@ -name: Release - -on: - # Releases are cut by hand, as in e2b-dev/E2B: merging a changeset to main no - # longer publishes on its own, so changesets accumulate until someone - # dispatches this. A release that publishes nothing leaves them intact, which - # makes a re-dispatch the recovery path too. - workflow_dispatch: {} - -concurrency: Release-${{ github.ref }}-foxtrot - -permissions: - id-token: write - contents: write - -jobs: - preflight: - name: Release preflight - runs-on: ubuntu-latest - outputs: - release: ${{ steps.version.outputs.release }} - charts: ${{ steps.charts.outputs.release }} - template: ${{ steps.template.outputs.release }} - itinerary: ${{ steps.itinerary.outputs.itinerary }} - steps: - - name: Check the ref - # `workflow_dispatch` offers every branch in the picker, and a feature - # branch carrying changesets would otherwise publish real packages and - # push the version bump to that branch. - if: github.ref != 'refs/heads/main' - env: - REF: ${{ github.ref }} - run: | - echo "::error::Releases must run on main; this run is on ${REF}." - exit 1 - - - name: Checkout Repo - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - - name: Parse .tool-versions - uses: wistia/parse-tool-versions@32f568a4ffd4bfa7720ebf93f171597d1ebc979a # v2.1.1 - with: - filename: '.tool-versions' - uppercase: 'true' - prefix: 'tool_version_' - - - name: Install pnpm - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 - id: pnpm-install - with: - version: ${{ env.TOOL_VERSION_PNPM }} - - - name: Setup Node - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 - with: - node-version: '${{ env.TOOL_VERSION_NODE }}' - registry-url: "https://registry.npmjs.org" - cache: pnpm - cache-dependency-path: pnpm-lock.yaml - - - name: Configure pnpm - run: | - pnpm config set auto-install-peers true - pnpm config set exclude-links-from-lockfile true - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Check if new version - id: version - run: | - IS_RELEASE=$(./.github/scripts/is_release.sh) - echo "release=$IS_RELEASE" >> "$GITHUB_OUTPUT" - - - name: Check Charts SDK Release - id: charts - if: steps.version.outputs.release == 'true' - run: | - IS_RELEASE=$(./.github/scripts/is_release_for_package.sh "@e2b/data-extractor") - echo "release=$IS_RELEASE" >> "$GITHUB_OUTPUT" - - - name: Check Template SDK Release - id: template - if: steps.version.outputs.release == 'true' - run: | - IS_RELEASE=$(./.github/scripts/is_release_for_package.sh "@e2b/code-interpreter-template") - echo "release=$IS_RELEASE" >> "$GITHUB_OUTPUT" - - - name: Build release itinerary - id: itinerary - if: steps.version.outputs.release == 'true' - # This only feeds the Slack notifications, so it must never be the thing - # that blocks a release; the messages fall back to a placeholder. - continue-on-error: true - run: | - pnpm changeset status --output=.cs-status.json - ITINERARY=$(node ./.github/scripts/build_release_itinerary.cjs .cs-status.json) - rm -f .cs-status.json - { - echo "itinerary<> "$GITHUB_OUTPUT" - - charts-release: - name: Charts release - needs: [preflight] - if: needs.preflight.outputs.charts == 'true' - runs-on: ubuntu-latest - outputs: - version: ${{ steps.output_version.outputs.version }} - steps: - - name: Checkout Repo - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - - name: Parse .tool-versions - uses: wistia/parse-tool-versions@32f568a4ffd4bfa7720ebf93f171597d1ebc979a # v2.1.1 - with: - filename: '.tool-versions' - uppercase: 'true' - prefix: 'tool_version_' - - - name: Install pnpm - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 - id: pnpm-install - with: - version: ${{ env.TOOL_VERSION_PNPM }} - - - name: Install uv - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0 - with: - version: '${{ env.TOOL_VERSION_UV }}' - python-version: '${{ env.TOOL_VERSION_PYTHON }}' - enable-cache: true - - - name: Configure pnpm - run: | - pnpm config set auto-install-peers true - pnpm config set exclude-links-from-lockfile true - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Create new versions - run: pnpm run version - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Release new versions - run: | - uv build - uv publish --check-url https://pypi.org/simple/ - working-directory: ./chart_data_extractor - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - UV_PUBLISH_TOKEN: ${{ secrets.CHARTS_PYPI_TOKEN }} - - - name: Output new version - id: output_version - working-directory: ./chart_data_extractor - run: | - echo "version=$(pnpm pkg get version --workspaces=false | tr -d \\\")" >> "$GITHUB_OUTPUT" - - build-docker-image: - name: Build Docker Image - runs-on: ubuntu-latest - needs: [preflight, charts-release] - if: (!cancelled()) && - !contains(needs.*.result, 'failure') && - (needs.preflight.outputs.template == 'true' || needs.preflight.outputs.charts == 'true') - steps: - - name: Checkout repository - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - - name: Parse .tool-versions - uses: wistia/parse-tool-versions@32f568a4ffd4bfa7720ebf93f171597d1ebc979a # v2.1.1 - with: - filename: '.tool-versions' - uppercase: 'true' - prefix: 'tool_version_' - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - - - name: Log in to DockerHub - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Set package version - working-directory: ./template - run: | - if [ -z "${{ needs.charts-release.outputs.version }}" ]; then - VERSION=$(cat ../chart_data_extractor/pyproject.toml | grep version | cut -d '"' -f 2) - else - VERSION=${{ needs.charts-release.outputs.version }} - fi - echo "Version: $VERSION" - - sed -i "s/e2b_charts/e2b_charts==${VERSION}/g" requirements.txt - - - name: Install uv - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0 - with: - version: '${{ env.TOOL_VERSION_UV }}' - python-version: '${{ env.TOOL_VERSION_PYTHON }}' - activate-environment: true - - - name: Install development dependencies - working-directory: ./template - run: uv pip install -r requirements-dev.txt - - - name: Build and push to DockerHub - working-directory: ./template - run: | - python build_docker.py | docker buildx build \ - --platform linux/amd64 \ - --push \ - --tag ${{ secrets.DOCKERHUB_USERNAME }}/code-interpreter:latest -f - . - - build-template: - name: Build E2B template - runs-on: ubuntu-latest - needs: [preflight, build-docker-image] - if: (!cancelled()) && - !contains(needs.*.result, 'failure') && - (needs.preflight.outputs.template == 'true' || needs.preflight.outputs.charts == 'true') - steps: - - name: Checkout repository - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - - name: Parse .tool-versions - uses: wistia/parse-tool-versions@32f568a4ffd4bfa7720ebf93f171597d1ebc979a # v2.1.1 - with: - filename: '.tool-versions' - uppercase: 'true' - prefix: 'tool_version_' - - - name: Install uv - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0 - with: - version: '${{ env.TOOL_VERSION_UV }}' - python-version: '${{ env.TOOL_VERSION_PYTHON }}' - activate-environment: true - - - name: Install development dependencies - working-directory: ./template - run: uv pip install -r requirements-dev.txt - - - name: Build E2B template - id: build-template - working-directory: ./template - run: | - python build_prod.py - env: - E2B_API_KEY: ${{ secrets.E2B_PROD_API_KEY }} - E2B_DOMAIN: ${{ vars.E2B_DOMAIN }} - - release: - # Every upstream job is listed, not just the last one: a job that fails makes - # its dependents *skip*, and a skipped job is not a failure — so gating on - # `needs.*.result` only works for the jobs this one depends on directly. - needs: [preflight, charts-release, build-docker-image, build-template] - if: (!cancelled()) && - !contains(needs.*.result, 'failure') && - needs.preflight.outputs.release == 'true' - name: Release - runs-on: ubuntu-latest - steps: - - uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1.12.0 - id: app-token - with: - app-id: ${{ vars.VERSION_BUMPER_APPID }} - private-key: ${{ secrets.VERSION_BUMPER_SECRET }} - - - name: Checkout Repo - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - with: - token: ${{ steps.app-token.outputs.token }} - - - name: Parse .tool-versions - uses: wistia/parse-tool-versions@32f568a4ffd4bfa7720ebf93f171597d1ebc979a # v2.1.1 - with: - filename: '.tool-versions' - uppercase: 'true' - prefix: 'tool_version_' - - - name: Install uv - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0 - with: - version: '${{ env.TOOL_VERSION_UV }}' - python-version: '${{ env.TOOL_VERSION_PYTHON }}' - enable-cache: true - - - uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0 - with: - version: ${{ env.TOOL_VERSION_PNPM }} - - - name: Setup Node.js 24 - # Deliberately ahead of the `node` baseline in .tool-versions: npm 11 is - # what OIDC trusted publishing needs (see #259). - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 - with: - node-version: "24.x" - registry-url: 'https://registry.npmjs.org' - cache: pnpm - - - name: Configure pnpm - run: | - pnpm config set auto-install-peers true - pnpm config set exclude-links-from-lockfile true - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Create new versions - run: pnpm run version - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Commit new versions - # Commit before publishing, because `changeset publish` tags whatever HEAD - # it publishes from — tagging afterwards is what left every tag on the - # commit before its own version bump (SDK-298). Nothing in the tree - # references the artifacts about to be uploaded — `changeset version` - # leaves `pnpm-lock.yaml` untouched here, since no workspace package - # depends on another — so the commit is already complete. It stays local - # until something is actually published, so a publish that uploads - # nothing leaves the branch untouched and the changesets intact for a - # re-run. - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - # `add -A`, not `commit -a`: `changeset version` writes each package's - # CHANGELOG.md as a new file the first time, which `-a` would drop. - git add -A - if git diff --cached --quiet; then - echo "::error::'changeset version' produced no changes, so there is no version bump to publish or tag." - exit 1 - fi - git commit -m "[skip ci] Release new versions" - - - name: Release new versions - uses: changesets/action@a45c4d594aa4e2c509dc14a9f2b3b67ba3780d0d # v1.9.0 - with: - publish: pnpm run publish - createGithubReleases: true - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NPM_TOKEN: "" # See https://github.com/changesets/changesets/issues/1152#issuecomment-3190884868 - PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} - - - name: Push new versions - # Gate on the tags rather than on whether the publish step succeeded: they - # are what has to end up reachable. `changeset publish` tags at HEAD and the - # step above pushes them to origin, so if any exist — even from a publish - # that then failed partway — the commit they point at has to land, or they - # hang off no branch, which is the SDK-298 breakage this change prevents. - if: always() - run: | - if [ -z "$(git tag --points-at HEAD)" ]; then - echo "Nothing was published; the version bump stays local and the changesets are intact for a re-run." - exit 0 - fi - - if ! git push; then - # A PR merged mid-release. Merge rather than rebase: the tags already - # point at this commit and rewriting it would strand them off the branch. - git fetch origin "${GITHUB_REF_NAME}" - git merge --no-edit FETCH_HEAD - git push - fi - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - report-start: - needs: [preflight] - if: needs.preflight.outputs.release == 'true' - name: Code Interpreter Release Started - Slack Notification - runs-on: ubuntu-latest - steps: - - name: Release Started - Slack Notification - uses: rtCamp/action-slack-notify@33ca3be66c6f378fe1610fd1d5258632dbed5e58 # v2.4.0 - env: - SLACK_COLOR: "#3aa3e3" - SLACK_MESSAGE: | - :rocket: A new release has been triggered :hourglass_flowing_sand: - - *Releasing:* - ${{ needs.preflight.outputs.itinerary || '• (itinerary unavailable)' }} - SLACK_TITLE: Code Interpreter Release Started - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} - SLACK_CHANNEL: "monitoring-releases" - - report-failure: - # `preflight` included so a failure there is reported too, whether or not - # `failure()` looks past this job's direct dependencies. - needs: [preflight, charts-release, build-docker-image, build-template, release] - if: failure() - name: Code Interpreter Release Failed - Slack Notification - runs-on: ubuntu-latest - steps: - - name: Release Failed - Slack Notification - uses: rtCamp/action-slack-notify@33ca3be66c6f378fe1610fd1d5258632dbed5e58 # v2.4.0 - env: - SLACK_COLOR: "#ff0000" - SLACK_MESSAGE: ":here-we-go-again: :bob-the-destroyer: We need :fix-parrot: ASAP :pray:" - SLACK_TITLE: Code Interpreter Release Failed - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} - SLACK_CHANNEL: "monitoring-releases" - - report-success: - needs: [preflight, release] - if: (!cancelled()) && needs.release.result == 'success' - name: Code Interpreter Release Succeeded - Slack Notification - runs-on: ubuntu-latest - steps: - - name: Release Succeeded - Slack Notification - uses: rtCamp/action-slack-notify@33ca3be66c6f378fe1610fd1d5258632dbed5e58 # v2.4.0 - env: - SLACK_COLOR: "#36a64f" - SLACK_MESSAGE: | - :tada: A new version has been released successfully! :ship-it-parrot: - - *Released:* - ${{ needs.preflight.outputs.itinerary || '• (itinerary unavailable)' }} - SLACK_TITLE: Code Interpreter Release Succeeded - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} - SLACK_CHANNEL: "monitoring-releases" diff --git a/.npmrc b/.npmrc deleted file mode 100644 index 4e82b99c..00000000 --- a/.npmrc +++ /dev/null @@ -1,6 +0,0 @@ -enable-pre-post-scripts=true -auto-install-peers=true -exclude-links-from-lockfile=true -prefer-workspace-packages=false -link-workspace-packages=false -engine-strict=true diff --git a/.tool-versions b/.tool-versions deleted file mode 100644 index 712ba38e..00000000 --- a/.tool-versions +++ /dev/null @@ -1,7 +0,0 @@ -python 3.10 -uv 0.10.0 -# Keep in sync with `packageManager` in package.json — pnpm self-switches to -# that version at runtime. -pnpm 10.34.5 -# Node is only used to run Changesets in CI. -node 20 diff --git a/Makefile b/Makefile deleted file mode 100644 index c1b25fea..00000000 --- a/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -start-template-server: - docker run --rm -e E2B_LOCAL=true -p 49999:49999 -it $$(python template/build_docker.py | docker build -q ./template -f -) - -kill-template-server: - docker kill $(shell docker ps --filter expose=49999 --format {{.ID}}) - -debug-template: - cd template && python build_debug.py && python debug_logs.py diff --git a/README.md b/README.md index 245673e0..6703f1b7 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Cover image ---> > [!NOTE] -> The `@e2b/code-interpreter` and `e2b-code-interpreter` SDK sources now live in the [E2B monorepo](https://github.com/e2b-dev/E2B), under `packages/code-interpreter-js` and `packages/code-interpreter-python`. Open SDK issues and pull requests there. This repository keeps the sandbox template and the chart data extractor. +> All source code now lives in the [E2B monorepo](https://github.com/e2b-dev/E2B): the JavaScript SDK is in [`packages/code-interpreter-js`](https://github.com/e2b-dev/E2B/tree/main/packages/code-interpreter-js), the Python SDK is in [`packages/code-interpreter-python`](https://github.com/e2b-dev/E2B/tree/main/packages/code-interpreter-python), the sandbox template is in [`templates/code-interpreter`](https://github.com/e2b-dev/E2B/tree/main/templates/code-interpreter), and `e2b-charts` is in [`packages/charts-python`](https://github.com/e2b-dev/E2B/tree/main/packages/charts-python). Please open issues and pull requests there. ## What is E2B? [E2B](https://e2b.dev/?utm_source=github&utm_medium=referral&utm_campaign=readme&utm_content=code-interpreter) is an open-source infrastructure that allows you to run AI-generated code in secure isolated sandboxes in the cloud. To start and control sandboxes, use our [JavaScript SDK](https://www.npmjs.com/package/@e2b/code-interpreter) or [Python SDK](https://pypi.org/project/e2b_code_interpreter). @@ -77,4 +77,4 @@ Visit [E2B documentation](https://docs.e2b.dev/?utm_source=github&utm_medium=ref Visit our [Cookbook](https://github.com/e2b-dev/e2b-cookbook/tree/main) to get inspired by examples with different LLMs and AI frameworks. ## Customizing the sandbox template -Need extra packages or a different runtime? You can build your own Code Interpreter sandbox template. See the [template guide](/template/README.md) for a step-by-step walkthrough of creating, building, and using a custom template (as well as building the production `code-interpreter-v1` template). +Need extra packages or a different runtime? You can build your own Code Interpreter sandbox template. See the [template guide](https://github.com/e2b-dev/E2B/blob/main/templates/code-interpreter/README.md) for a step-by-step walkthrough of creating, building, and using a custom template (as well as building the production `code-interpreter-v1` template). diff --git a/chart_data_extractor/LICENSE b/chart_data_extractor/LICENSE deleted file mode 100644 index 4aa6529d..00000000 --- a/chart_data_extractor/LICENSE +++ /dev/null @@ -1,9 +0,0 @@ -MIT License - -Copyright (c) 2025 FOUNDRYLABS, INC. - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/chart_data_extractor/README.md b/chart_data_extractor/README.md deleted file mode 100644 index 7c23e47f..00000000 --- a/chart_data_extractor/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Extracting Data for Code Interpreter SDK - -This package is a utility used to extract data in the Code Interpreter SDK from, e.g., DataFrames and matplotlib plots. diff --git a/chart_data_extractor/e2b_charts/__init__.py b/chart_data_extractor/e2b_charts/__init__.py deleted file mode 100644 index adb4954c..00000000 --- a/chart_data_extractor/e2b_charts/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .main import chart_figure_to_chart, chart_figure_to_dict diff --git a/chart_data_extractor/e2b_charts/charts/__init__.py b/chart_data_extractor/e2b_charts/charts/__init__.py deleted file mode 100644 index 0cfbebd3..00000000 --- a/chart_data_extractor/e2b_charts/charts/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .base import ChartType, Chart -from .bars import BarChart, BoxAndWhiskerChart -from .pie import PieChart -from .planar import ScatterChart, LineChart diff --git a/chart_data_extractor/e2b_charts/charts/bars.py b/chart_data_extractor/e2b_charts/charts/bars.py deleted file mode 100644 index 3d7a9437..00000000 --- a/chart_data_extractor/e2b_charts/charts/bars.py +++ /dev/null @@ -1,140 +0,0 @@ -from typing import Literal, List - -from matplotlib.axes import Axes -from pydantic import BaseModel, Field - -from .base import Chart2D, ChartType -from ..utils.rounding import dynamic_round - - -class BarData(BaseModel): - label: str - group: str - value: float - - -class BarChart(Chart2D): - type: Literal[ChartType.BAR] = ChartType.BAR - - elements: List[BarData] = Field(default_factory=list) - - def _extract_info(self, ax: Axes) -> None: - super()._extract_info(ax) - for container in ax.containers: - group_label = container.get_label() - if group_label.startswith("_container"): - number = int(group_label[10:]) - group_label = f"Group {number}" - - heights = [rect.get_height() for rect in container] - if all(height == heights[0] for height in heights): - # vertical bars - self._change_orientation() - labels = [label.get_text() for label in ax.get_yticklabels()] - values = [rect.get_width() for rect in container] - else: - # horizontal bars - labels = [label.get_text() for label in ax.get_xticklabels()] - values = heights - for label, value in zip(labels, values): - bar = BarData(label=label, value=value, group=group_label) - self.elements.append(bar) - - -class BoxAndWhiskerData(BaseModel): - label: str - min: float - first_quartile: float - median: float - third_quartile: float - max: float - outliers: List[float] - - -class BoxAndWhiskerChart(Chart2D): - type: Literal[ChartType.BOX_AND_WHISKER] = ChartType.BOX_AND_WHISKER - - elements: List[BoxAndWhiskerData] = Field(default_factory=list) - - def _extract_info(self, ax: Axes) -> None: - super()._extract_info(ax) - labels = [item.get_text() for item in ax.get_xticklabels()] - - boxes = [] - for label, box in zip(labels, ax.patches): - vertices = box.get_path().vertices - x_vertices = [dynamic_round(x) for x in vertices[:, 0]] - y_vertices = [dynamic_round(y) for y in vertices[:, 1]] - x = min(x_vertices) - y = min(y_vertices) - boxes.append( - { - "x": x, - "y": y, - "label": label, - "width": max(x_vertices) - x, - "height": max(y_vertices) - y, - "outliers": [], - } - ) - - orientation = "horizontal" - if all(box["height"] == boxes[0]["height"] for box in boxes): - orientation = "vertical" - - if orientation == "vertical": - self._change_orientation() - for box in boxes: - box["x"], box["y"] = box["y"], box["x"] - box["width"], box["height"] = box["height"], box["width"] - - for i, line in enumerate(ax.lines): - xdata = [dynamic_round(x) for x in line.get_xdata()] - ydata = [dynamic_round(y) for y in line.get_ydata()] - - if orientation == "vertical": - xdata, ydata = ydata, xdata - - if len(xdata) == 1: - for box in boxes: - if box["x"] <= xdata[0] <= box["x"] + box["width"]: - break - else: - continue - - box["outliers"].append(ydata[0]) - if len(ydata) != 2: - continue - for box in boxes: - if box["x"] <= xdata[0] <= xdata[1] <= box["x"] + box["width"]: - break - else: - continue - - if ( - # Check if the line is inside the box, prevent floating point errors - ydata[0] == ydata[1] - and box["y"] <= ydata[0] <= box["y"] + box["height"] - ): - box["median"] = ydata[0] - continue - - lower_value = min(ydata) - upper_value = max(ydata) - if upper_value == box["y"]: - box["whisker_lower"] = lower_value - elif lower_value == box["y"] + box["height"]: - box["whisker_upper"] = upper_value - - self.elements = [ - BoxAndWhiskerData( - label=box["label"], - min=box["whisker_lower"], - first_quartile=box["y"], - median=box["median"], - third_quartile=box["y"] + box["height"], - max=box["whisker_upper"], - outliers=box["outliers"], - ) - for box in boxes - ] diff --git a/chart_data_extractor/e2b_charts/charts/base.py b/chart_data_extractor/e2b_charts/charts/base.py deleted file mode 100644 index 0985a9d8..00000000 --- a/chart_data_extractor/e2b_charts/charts/base.py +++ /dev/null @@ -1,75 +0,0 @@ -import enum -import re -from typing import Optional, List, Any - -from matplotlib.axes import Axes -from pydantic import BaseModel, Field - - -class ChartType(str, enum.Enum): - LINE = "line" - SCATTER = "scatter" - BAR = "bar" - PIE = "pie" - BOX_AND_WHISKER = "box_and_whisker" - SUPERCHART = "superchart" - UNKNOWN = "unknown" - - -class Chart(BaseModel): - type: ChartType - title: Optional[str] = None - - elements: List[Any] = Field(default_factory=list) - - def __init__(self, ax: Optional[Axes] = None, **kwargs): - super().__init__(**kwargs) - if ax: - self._extract_info(ax) - - def _extract_info(self, ax: Axes) -> None: - """ - Function to extract information for Chart - """ - title = ax.get_title() - if title == "": - title = None - - self.title = title - - -class Chart2D(Chart): - x_label: Optional[str] = None - y_label: Optional[str] = None - x_unit: Optional[str] = None - y_unit: Optional[str] = None - - def _extract_info(self, ax: Axes) -> None: - """ - Function to extract information for Chart2D - """ - super()._extract_info(ax) - x_label = ax.get_xlabel() - if x_label == "": - x_label = None - self.x_label = x_label - - y_label = ax.get_ylabel() - if y_label == "": - y_label = None - self.y_label = y_label - - regex = r"\s\((.*?)\)|\[(.*?)\]" - if self.x_label: - match = re.search(regex, self.x_label) - if match: - self.x_unit = match.group(1) or match.group(2) - - if self.y_label: - match = re.search(regex, self.y_label) - if match: - self.y_unit = match.group(1) or match.group(2) - - def _change_orientation(self): - self.x_label, self.y_label = self.y_label, self.x_label - self.x_unit, self.y_unit = self.y_unit, self.x_unit diff --git a/chart_data_extractor/e2b_charts/charts/pie.py b/chart_data_extractor/e2b_charts/charts/pie.py deleted file mode 100644 index 2581830b..00000000 --- a/chart_data_extractor/e2b_charts/charts/pie.py +++ /dev/null @@ -1,36 +0,0 @@ -from decimal import Decimal -from typing import Literal, List - -from matplotlib.axes import Axes -from pydantic import BaseModel, Field - -from .base import Chart, ChartType -from ..utils.rounding import dynamic_round - - -class PieData(BaseModel): - label: str - angle: float - radius: float - - -class PieChart(Chart): - type: Literal[ChartType.PIE] = ChartType.PIE - - elements: List[PieData] = Field(default_factory=list) - - def _extract_info(self, ax: Axes) -> None: - super()._extract_info(ax) - - for wedge in ax.patches: - pie_data = PieData( - label=wedge.get_label(), - angle=abs( - dynamic_round( - Decimal(float(wedge.theta2)) - Decimal(float(wedge.theta1)) - ) - ), - radius=wedge.r, - ) - - self.elements.append(pie_data) diff --git a/chart_data_extractor/e2b_charts/charts/planar.py b/chart_data_extractor/e2b_charts/charts/planar.py deleted file mode 100644 index bb7d025d..00000000 --- a/chart_data_extractor/e2b_charts/charts/planar.py +++ /dev/null @@ -1,132 +0,0 @@ -from datetime import date -from typing import List, Tuple, Union, Sequence, Any, Literal - -import matplotlib -import numpy -from matplotlib.axes import Axes -from matplotlib.dates import _SwitchableDateConverter -from pydantic import BaseModel, field_validator, Field - -from .base import Chart2D, ChartType -from ..utils import is_grid_line - - -class PointData(BaseModel): - label: str - points: List[Tuple[Union[str, float], Union[str, float]]] - - @field_validator("points", mode="before") - @classmethod - def transform_points( - cls, value - ) -> List[Tuple[Union[str, float], Union[str, float]]]: - parsed_value = [] - for x, y in value: - x = cls._parse_point(x) - y = cls._parse_point(y) - parsed_value.append((x, y)) - return parsed_value - - @staticmethod - def _parse_point(point): - if isinstance(point, date): - return point.isoformat() - if isinstance(point, numpy.datetime64): - return point.astype("datetime64[s]").astype(str) - return point - - -class PointChart(Chart2D): - x_ticks: List[Union[str, float]] = Field(default_factory=list) - x_tick_labels: List[str] = Field(default_factory=list) - x_scale: str = Field(default="linear") - - y_ticks: List[Union[str, float]] = Field(default_factory=list) - y_tick_labels: List[str] = Field(default_factory=list) - y_scale: str = Field(default="linear") - - elements: List[PointData] = Field(default_factory=list) - - def _extract_info(self, ax: Axes) -> None: - """ - Function to extract information for PointChart - """ - super()._extract_info(ax) - - self.x_tick_labels = [label.get_text() for label in ax.get_xticklabels()] - - x_ticks = ax.get_xticks() - self.x_ticks = self._extract_ticks_info(ax.xaxis.converter, x_ticks) - self.x_scale = self._detect_scale( - ax.xaxis.converter, ax.get_xscale(), self.x_ticks, self.x_tick_labels - ) - - self.y_tick_labels = [label.get_text() for label in ax.get_yticklabels()] - self.y_ticks = self._extract_ticks_info(ax.yaxis.converter, ax.get_yticks()) - self.y_scale = self._detect_scale( - ax.yaxis.converter, ax.get_yscale(), self.y_ticks, self.y_tick_labels - ) - - @staticmethod - def _detect_scale(converter, scale: str, ticks: Sequence, labels: Sequence) -> str: - # If the converter is a date converter, it's a datetime scale - if isinstance(converter, _SwitchableDateConverter): - return "datetime" - - # If the scale is not linear, it can't be categorical - if scale != "linear": - return scale - - # If all the ticks are integers and are in order from 0 to n-1 - # and the labels aren't corresponding to the ticks, it's categorical - for i, tick_and_label in enumerate(zip(ticks, labels)): - tick, label = tick_and_label - if isinstance(tick, (int, float)) and tick == i and str(i) != label: - continue - # Found a tick, which wouldn't be in a categorical scale - return "linear" - - return "categorical" - - @staticmethod - def _extract_ticks_info(converter: Any, ticks: Sequence) -> list: - if isinstance(converter, _SwitchableDateConverter): - return [matplotlib.dates.num2date(tick).isoformat() for tick in ticks] - else: - example_tick = ticks[0] - - if isinstance(example_tick, (int, float)): - return [float(tick) for tick in ticks] - else: - return list(ticks) - - -class LineChart(PointChart): - type: Literal[ChartType.LINE] = ChartType.LINE - - def _extract_info(self, ax: Axes) -> None: - super()._extract_info(ax) - - for line in ax.get_lines(): - if is_grid_line(line): - continue - label = line.get_label() - if label.startswith("_child"): - number = int(label[6:]) - label = f"Line {number}" - - points = [(x, y) for x, y in zip(line.get_xdata(), line.get_ydata())] - line_data = PointData(label=label, points=points) - self.elements.append(line_data) - - -class ScatterChart(PointChart): - type: Literal[ChartType.SCATTER] = ChartType.SCATTER - - def _extract_info(self, ax: Axes) -> None: - super()._extract_info(ax) - - for collection in ax.collections: - points = [(x, y) for x, y in collection.get_offsets()] - scatter_data = PointData(label=collection.get_label(), points=points) - self.elements.append(scatter_data) diff --git a/chart_data_extractor/e2b_charts/main.py b/chart_data_extractor/e2b_charts/main.py deleted file mode 100644 index 7f51dbbd..00000000 --- a/chart_data_extractor/e2b_charts/main.py +++ /dev/null @@ -1,119 +0,0 @@ -from typing import Optional, List, Literal - -from matplotlib.axes import Axes -from matplotlib.collections import PathCollection -from matplotlib.lines import Line2D -from matplotlib.patches import Rectangle, Wedge, PathPatch -from matplotlib.pyplot import Figure - -from matplotlib.text import Text -from pydantic import Field - -from .charts import ( - ChartType, - Chart, - LineChart, - BarChart, - BoxAndWhiskerChart, - PieChart, - ScatterChart, -) -from .utils.filtering import is_grid_line - - -class SuperChart(Chart): - type: Literal[ChartType.SUPERCHART] = ChartType.SUPERCHART - elements: List[ - LineChart | ScatterChart | BarChart | PieChart | BoxAndWhiskerChart - ] = Field(default_factory=list) - - def __init__(self, figure: Figure): - title = figure.get_suptitle() - super().__init__(title=title) - - self.elements = [get_chart_from_ax(ax) for ax in figure.axes] - - -def _get_type_of_chart(ax: Axes) -> ChartType: - objects = list(filter(lambda obj: not isinstance(obj, Text), ax._children)) - - # Check for Line plots - if all(isinstance(line, Line2D) for line in objects): - return ChartType.LINE - - if all(isinstance(box_or_path, (PathPatch, Line2D)) for box_or_path in objects): - return ChartType.BOX_AND_WHISKER - - filtered = [] - for obj in objects: - if isinstance(obj, Line2D) and is_grid_line(obj): - continue - filtered.append(obj) - - objects = filtered - - # Check for Scatter plots - if all(isinstance(path, PathCollection) for path in objects): - return ChartType.SCATTER - - # Check for Pie plots - if all(isinstance(artist, Wedge) for artist in objects): - return ChartType.PIE - - # Check for Bar plots - if all(isinstance(rect, Rectangle) for rect in objects): - return ChartType.BAR - - return ChartType.UNKNOWN - - -def get_chart_from_ax( - ax: Axes, -) -> LineChart | ScatterChart | BarChart | PieChart | BoxAndWhiskerChart | Chart: - chart_type = _get_type_of_chart(ax) - - if chart_type == ChartType.LINE: - chart = LineChart(ax=ax) - elif chart_type == ChartType.SCATTER: - chart = ScatterChart(ax=ax) - elif chart_type == ChartType.BAR: - chart = BarChart(ax=ax) - elif chart_type == ChartType.PIE: - chart = PieChart(ax=ax) - elif chart_type == ChartType.BOX_AND_WHISKER: - chart = BoxAndWhiskerChart(ax=ax) - else: - chart = Chart(ax=ax, type=chart_type) - - return chart - - -def is_figure_blank(axes: List[Axes]) -> bool: - """Check if a Matplotlib figure is blank (has no user-added artists).""" - for ax in axes: - if ax.has_data(): - return False # The figure contains user-added data - return True # No data found, figure is blank - - -def chart_figure_to_chart(figure: Figure) -> Optional[Chart]: - """ - This method is used to extract data from the figure object to a dictionary - """ - # Get all Axes objects from the Figure - axes = figure.get_axes() - - if not axes or is_figure_blank(axes): - return - elif len(axes) > 1: - return SuperChart(figure=figure) - else: - ax = axes[0] - return get_chart_from_ax(ax) - - -def chart_figure_to_dict(figure: Figure) -> dict: - chart = chart_figure_to_chart(figure) - if chart: - return chart.model_dump() - return {} diff --git a/chart_data_extractor/e2b_charts/utils/__init__.py b/chart_data_extractor/e2b_charts/utils/__init__.py deleted file mode 100644 index 7822a91f..00000000 --- a/chart_data_extractor/e2b_charts/utils/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .filtering import is_grid_line diff --git a/chart_data_extractor/e2b_charts/utils/filtering.py b/chart_data_extractor/e2b_charts/utils/filtering.py deleted file mode 100644 index 8394c27b..00000000 --- a/chart_data_extractor/e2b_charts/utils/filtering.py +++ /dev/null @@ -1,16 +0,0 @@ -from matplotlib.lines import Line2D - - -def is_grid_line(line: Line2D) -> bool: - x_data = line.get_xdata() - if len(x_data) != 2: - return False - - y_data = line.get_ydata() - if len(y_data) != 2: - return False - - if x_data[0] == x_data[1] or y_data[0] == y_data[1]: - return True - - return False diff --git a/chart_data_extractor/e2b_charts/utils/rounding.py b/chart_data_extractor/e2b_charts/utils/rounding.py deleted file mode 100644 index 4efbb667..00000000 --- a/chart_data_extractor/e2b_charts/utils/rounding.py +++ /dev/null @@ -1,13 +0,0 @@ -from decimal import Decimal, localcontext - - -def dynamic_round(number): - # Convert to Decimal for precise control - decimal_number = Decimal(str(number)) - - # Dynamically determine precision based on magnitude - precision = max(1, 8 - decimal_number.adjusted()) # 8 digits of precision - - with localcontext() as ctx: - ctx.prec = precision # Set the dynamic precision - return +decimal_number # The + operator applies rounding diff --git a/chart_data_extractor/package.json b/chart_data_extractor/package.json deleted file mode 100644 index d939fe7f..00000000 --- a/chart_data_extractor/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "@e2b/data-extractor", - "private": true, - "version": "1.0.0", - "scripts": { - "test": "uv run pytest -n 4 --verbose -x", - "example": "uv run python3 example.py", - "postVersion": "uv version $(pnpm pkg get version --workspaces=false | tr -d \\\")", - "pretest": "uv sync", - "lint": "uv run ruff check .", - "format": "uv run ruff format ." - }, - "devDependencies": { - "@typescript-eslint/eslint-plugin": "^7.11.0", - "@typescript-eslint/parser": "^7.11.0", - "eslint": "^8.57.1" - } -} diff --git a/chart_data_extractor/pyproject.toml b/chart_data_extractor/pyproject.toml deleted file mode 100644 index 84541f93..00000000 --- a/chart_data_extractor/pyproject.toml +++ /dev/null @@ -1,38 +0,0 @@ -[project] -name = "e2b-charts" -version = "1.0.0" -description = "Package for extracting data for E2B Code Interpreter" -authors = [{ name = "e2b", email = "hello@e2b.dev" }] -requires-python = ">=3.10" -readme = "README.md" -license = "MIT" -license-files = ["LICENSE"] -dependencies = [ - "numpy>=2.2.6,<3", - "matplotlib>=3.10.3,<4", - "pydantic>=2.9.1,<3", -] - -[project.urls] -Homepage = "https://e2b.dev/" -Repository = "https://github.com/e2b-dev/e2b-code-interpreter/tree/python" -"Bug Tracker" = "https://github.com/e2b-dev/code-interpreter/issues" - -[dependency-groups] -dev = [ - "pytest>=9.0.3,<10", - "python-dotenv>=1.2.1,<2", - "pytest-dotenv>=0.5.2,<0.6", - "ruff>=0.11.12,<0.12", -] - -[tool.uv.build-backend] -module-name = ["e2b_charts"] -module-root = "" - -[build-system] -requires = ["uv_build>=0.10.0,<0.11.0"] -build-backend = "uv_build" - -[tool.ruff.lint] -ignore = ["F401", "F403"] diff --git a/chart_data_extractor/tests/charts/test_bar.py b/chart_data_extractor/tests/charts/test_bar.py deleted file mode 100644 index 246b4d62..00000000 --- a/chart_data_extractor/tests/charts/test_bar.py +++ /dev/null @@ -1,49 +0,0 @@ -import matplotlib.pyplot as plt - -from e2b_charts import chart_figure_to_chart -from e2b_charts.charts import BarChart, ChartType - - -def _prep_chart_figure(): - # Prepare data - authors = ["Author A", "Author B", "Author C", "Author D"] - sales = [100, 200, 300, 400] - - # Create and customize the bar chart - plt.figure(figsize=(10, 6)) - plt.bar(authors, sales, label="Books Sold", color="blue") - plt.xlabel("Authors") - plt.ylabel("Number of Books Sold") - plt.title("Book Sales by Authors") - - # Display the chart - plt.tight_layout() - return plt.gcf() - - -def test_chart_bar(): - figure = _prep_chart_figure() - chart = chart_figure_to_chart(figure) - assert chart - - assert isinstance(chart, BarChart) - assert chart.type == ChartType.BAR - assert chart.title == "Book Sales by Authors" - - assert chart.x_label == "Authors" - assert chart.y_label == "Number of Books Sold" - - assert chart.x_unit is None - assert chart.y_unit is None - - bars = chart.elements - assert len(bars) == 4 - - assert [bar.value for bar in bars] == [100, 200, 300, 400] - assert [bar.label for bar in bars] == [ - "Author A", - "Author B", - "Author C", - "Author D", - ] - assert [bar.group for bar in bars] == ["Books Sold"] * 4 diff --git a/chart_data_extractor/tests/charts/test_blank.py b/chart_data_extractor/tests/charts/test_blank.py deleted file mode 100644 index 7fb95c43..00000000 --- a/chart_data_extractor/tests/charts/test_blank.py +++ /dev/null @@ -1,9 +0,0 @@ -import matplotlib.pyplot as plt - -from e2b_charts import chart_figure_to_chart - - -def test_blank_chart(): - figure, _ = plt.subplots() - chart = chart_figure_to_chart(figure) - assert chart is None diff --git a/chart_data_extractor/tests/charts/test_box_and_whiskers.py b/chart_data_extractor/tests/charts/test_box_and_whiskers.py deleted file mode 100644 index 799e3ffd..00000000 --- a/chart_data_extractor/tests/charts/test_box_and_whiskers.py +++ /dev/null @@ -1,57 +0,0 @@ -import matplotlib.pyplot as plt - -from e2b_charts import chart_figure_to_chart -from e2b_charts.charts import BoxAndWhiskerChart, ChartType - - -def _prep_chart_figure(): - # Sample data - data = { - "Class A": [85, 90, 78, 92, 88], - "Class B": [95, 89, 76, 91, 84, 87], - "Class C": [75, 82, 88, 79, 86], - } - - # Create figure and axis - fig, ax = plt.subplots(figsize=(10, 6)) - - # Plot box plot - ax.boxplot(data.values(), tick_labels=data.keys()) - - # Customize plot - ax.set_title("Exam Scores Distribution") - ax.set_xlabel("Class") - ax.set_ylabel("Score") - - # Set custom colors - ax.boxplot(data.values(), tick_labels=data.keys(), patch_artist=True) - - # Adjust layout and show plot - plt.tight_layout() - return plt.gcf() - - -def test_box_and_whiskers(): - figure = _prep_chart_figure() - chart = chart_figure_to_chart(figure) - assert chart - - assert isinstance(chart, BoxAndWhiskerChart) - assert chart.type == ChartType.BOX_AND_WHISKER - assert chart.title == "Exam Scores Distribution" - - assert chart.x_label == "Class" - assert chart.y_label == "Score" - - assert chart.x_unit is None - assert chart.y_unit is None - - bars = chart.elements - assert len(bars) == 3 - - assert all(isinstance(bar.min, float) for bar in bars) - assert all(isinstance(bar.first_quartile, float) for bar in bars) - assert all(isinstance(bar.median, float) for bar in bars) - assert all(isinstance(bar.third_quartile, float) for bar in bars) - assert all(isinstance(bar.max, float) for bar in bars) - assert all(isinstance(bar.label, str) for bar in bars) diff --git a/chart_data_extractor/tests/charts/test_categorical_scale.py b/chart_data_extractor/tests/charts/test_categorical_scale.py deleted file mode 100644 index 12d87d23..00000000 --- a/chart_data_extractor/tests/charts/test_categorical_scale.py +++ /dev/null @@ -1,25 +0,0 @@ -import matplotlib.pyplot as plt - -from e2b_charts import chart_figure_to_chart -from e2b_charts.charts import LineChart - - -def _prep_chart_figure(): - x = [1, 2, 3, 4, 5] - y = ["A", "B", "C", "D", "E"] - - # Create the plot - plt.figure(figsize=(10, 6)) - plt.plot(x, y) - - return plt.gcf() - - -def test_categorical_scale(): - figure = _prep_chart_figure() - chart = chart_figure_to_chart(figure) - assert chart - - assert isinstance(chart, LineChart) - assert chart.x_scale == "linear" - assert chart.y_scale == "categorical" diff --git a/chart_data_extractor/tests/charts/test_datetime_scale.py b/chart_data_extractor/tests/charts/test_datetime_scale.py deleted file mode 100644 index a851d16b..00000000 --- a/chart_data_extractor/tests/charts/test_datetime_scale.py +++ /dev/null @@ -1,30 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import datetime - -from e2b_charts import chart_figure_to_chart -from e2b_charts.charts import LineChart - - -def _prep_chart_figure(): - # Generate x values - dates = [ - datetime.date(2023, 9, 1) + datetime.timedelta(seconds=i) for i in range(100) - ] - y_sin = np.sin(np.linspace(0, 2 * np.pi, 100)) - - # Create the plot - plt.figure(figsize=(10, 6)) - plt.plot(dates, y_sin, label="sin(x)") - - return plt.gcf() - - -def test_datetime_scale(): - figure = _prep_chart_figure() - chart = chart_figure_to_chart(figure) - assert chart - - assert isinstance(chart, LineChart) - assert chart.x_scale == "datetime" - assert chart.y_scale == "linear" diff --git a/chart_data_extractor/tests/charts/test_line.py b/chart_data_extractor/tests/charts/test_line.py deleted file mode 100644 index ed58e655..00000000 --- a/chart_data_extractor/tests/charts/test_line.py +++ /dev/null @@ -1,74 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import datetime - -from e2b_charts import chart_figure_to_chart -from e2b_charts.charts import LineChart - - -def _prep_chart_figure(): - # Generate x values - dates = [ - datetime.date(2023, 9, 1) + datetime.timedelta(seconds=i) for i in range(100) - ] - - x = np.linspace(0, 2 * np.pi, 100) - # Calculate y values - y_sin = np.sin(x) - y_cos = np.cos(x) - - # Create the plot - plt.figure(figsize=(10, 6)) - plt.plot(dates, y_sin, label="sin(x)") - plt.plot(dates, y_cos, label="cos(x)") - - # Add labels and title - plt.xlabel("Time (s)") - plt.ylabel("Amplitude (Hz)") - plt.title("Plot of sin(x) and cos(x)") - - return plt.gcf() - - -def test_line_chart(): - figure = _prep_chart_figure() - chart = chart_figure_to_chart(figure) - assert chart - - assert isinstance(chart, LineChart) - assert chart.title == "Plot of sin(x) and cos(x)" - - assert chart.x_label == "Time (s)" - assert chart.y_label == "Amplitude (Hz)" - - assert chart.x_unit == "s" - assert chart.y_unit == "Hz" - - assert chart.x_scale == "datetime" - assert chart.y_scale == "linear" - - assert all(isinstance(x, str) for x in chart.x_ticks) - parsed_date = datetime.datetime.fromisoformat(chart.x_ticks[0]) - assert isinstance(parsed_date, datetime.datetime) - assert all(isinstance(y, float) for y in chart.y_ticks) - - assert all(isinstance(x, str) for x in chart.y_tick_labels) - assert all(isinstance(y, str) for y in chart.y_tick_labels) - - lines = chart.elements - assert len(lines) == 2 - - first_line = lines[0] - assert first_line.label == "sin(x)" - assert len(first_line.points) == 100 - assert all(isinstance(point, tuple) for point in first_line.points) - assert all( - isinstance(x, str) and isinstance(y, float) for x, y in first_line.points - ) - - parsed_date = datetime.datetime.fromisoformat(first_line.points[0][0]) - assert isinstance(parsed_date, datetime.datetime) - - second_line = lines[1] - assert second_line.label == "cos(x)" - assert len(second_line.points) == 100 diff --git a/chart_data_extractor/tests/charts/test_log_graph.py b/chart_data_extractor/tests/charts/test_log_graph.py deleted file mode 100644 index b15cb72b..00000000 --- a/chart_data_extractor/tests/charts/test_log_graph.py +++ /dev/null @@ -1,63 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt - -from e2b_charts import chart_figure_to_chart -from e2b_charts.charts import LineChart - - -def _prep_chart_figure(): - # Generate x values - x = np.linspace(0, 100, 100) - # Calculate y values - y = np.exp(x) - - # Create the plot - plt.figure(figsize=(10, 6)) - plt.plot(x, y, label="y = e^x") - - # Set log scale for the y-axis - plt.yscale("log") - - # Add labels and title - plt.xlabel("X-axis") - plt.ylabel("Y-axis (log scale)") - plt.title("Chart with Log Scale on Y-axis") - - plt.legend() - plt.grid(True) - - return plt.gcf() - - -def test_log_chart(): - figure = _prep_chart_figure() - chart = chart_figure_to_chart(figure) - assert chart - - assert isinstance(chart, LineChart) - assert chart.title == "Chart with Log Scale on Y-axis" - - assert chart.x_label == "X-axis" - assert chart.y_label == "Y-axis (log scale)" - - assert chart.x_unit is None - assert chart.y_unit == "log scale" - - assert chart.x_scale == "linear" - assert chart.y_scale == "log" - - assert all(isinstance(x, float) for x in chart.x_ticks) - assert all(isinstance(y, float) for y in chart.y_ticks) - - assert all(isinstance(x, str) for x in chart.x_tick_labels) - assert all(isinstance(y, str) for y in chart.y_tick_labels) - - lines = chart.elements - assert len(lines) == 1 - - line = lines[0] - assert line.label == "y = e^x" - assert len(line.points) == 100 - - assert all(isinstance(x, tuple) for x in line.points) - assert all(isinstance(x, float) and isinstance(y, float) for x, y in line.points) diff --git a/chart_data_extractor/tests/charts/test_pie.py b/chart_data_extractor/tests/charts/test_pie.py deleted file mode 100644 index 28e7ac99..00000000 --- a/chart_data_extractor/tests/charts/test_pie.py +++ /dev/null @@ -1,53 +0,0 @@ -import matplotlib.pyplot as plt - -from e2b_charts import chart_figure_to_chart -from e2b_charts.charts import PieChart - - -def _prep_chart_figure(): - # Step 1: Define the data for the pie chart - categories = ["No", "No, in blue"] - sizes = [90, 10] - - # Step 2: Create the figure and axis objects - fig, ax = plt.subplots(figsize=(8, 8)) - - plt.xlabel("x") - plt.ylabel("y") - - # Step 3: Create the pie chart - ax.pie( - sizes, - labels=categories, - autopct="%1.1f%%", - startangle=90, - colors=plt.cm.Pastel1.colors[: len(categories)], - ) - - # Step 4: Add title and legend - ax.axis("equal") # Equal aspect ratio ensures that pie is drawn as a circle - plt.title("Will I wake up early tomorrow?") - - return plt.gcf() - - -def test_pie_chart(): - figure = _prep_chart_figure() - chart = chart_figure_to_chart(figure) - assert chart - - assert isinstance(chart, PieChart) - - assert chart.title == "Will I wake up early tomorrow?" - - assert len(chart.elements) == 2 - - first_data = chart.elements[0] - assert first_data.label == "No" - assert first_data.angle == 324 - assert first_data.radius == 1 - - second_data = chart.elements[1] - assert second_data.label == "No, in blue" - assert second_data.angle == 36 - assert second_data.radius == 1 diff --git a/chart_data_extractor/tests/charts/test_scatter.py b/chart_data_extractor/tests/charts/test_scatter.py deleted file mode 100644 index e57582f1..00000000 --- a/chart_data_extractor/tests/charts/test_scatter.py +++ /dev/null @@ -1,58 +0,0 @@ -import matplotlib.pyplot as plt -import numpy as np - -from e2b_charts import chart_figure_to_chart -from e2b_charts.charts import ScatterChart - - -def _prep_chart_figure(): - # Create data - N = 5 - x1 = np.random.rand(N) - y1 = np.random.rand(N) - x2 = np.random.rand(2 * N) - y2 = np.random.rand(2 * N) - - plt.figure(figsize=(10, 6)) - - plt.xlabel("A") - plt.ylabel("B") - - plt.scatter(x1, y1, c="blue", label="Dataset 1") - plt.scatter(x2, y2, c="red", label="Dataset 2") - - return plt.gcf() - - -def test_scatter_chart(): - figure = _prep_chart_figure() - chart = chart_figure_to_chart(figure) - assert chart - - assert isinstance(chart, ScatterChart) - - assert chart.title is None - assert chart.x_label == "A" - assert chart.y_label == "B" - - assert chart.x_scale == "linear" - assert chart.y_scale == "linear" - - assert all(isinstance(x, float) for x in chart.x_ticks) - assert all(isinstance(y, float) for y in chart.y_ticks) - - assert all(isinstance(x, str) for x in chart.y_tick_labels) - assert all(isinstance(y, str) for y in chart.y_tick_labels) - - assert len(chart.elements) == 2 - - first_data = chart.elements[0] - assert first_data.label == "Dataset 1" - assert len(first_data.points) == 5 - print(first_data.points) - assert all(isinstance(x, tuple) for x in first_data.points) - - second_data = chart.elements[1] - assert second_data.label == "Dataset 2" - assert len(second_data.points) == 10 - assert all(isinstance(x, tuple) for x in second_data.points) diff --git a/chart_data_extractor/tests/charts/test_supergraph.py b/chart_data_extractor/tests/charts/test_supergraph.py deleted file mode 100644 index ca3e569e..00000000 --- a/chart_data_extractor/tests/charts/test_supergraph.py +++ /dev/null @@ -1,66 +0,0 @@ -import matplotlib.pyplot as plt -import numpy as np - -from e2b_charts import chart_figure_to_chart -from e2b_charts.charts import ( - ChartType, - LineChart, - ScatterChart, -) -from e2b_charts.main import SuperChart - - -def _prep_chart_figure(): - # Data for plotting - x1 = np.linspace(0, 10, 100) - y1 = np.sin(x1) - - # Create a figure with multiple subplots - fig, axs = plt.subplots(1, 2, figsize=(10, 8)) - fig.suptitle("Multiple Charts Example", fontsize=16) - - # Plotting on the different axes - axs[0].plot(x1, y1, "r") - axs[0].set_title("Sine Wave") - axs[0].grid(True) - - N = 5 - x2 = np.random.rand(N) - y2 = np.random.rand(N) - - axs[1].scatter(x2, y2, c="blue", label="Dataset 1") - axs[1].set_xlabel("X") - axs[1].set_ylabel("Y") - axs[1].set_title("Scatter Plot") - axs[1].grid(True) - - return plt.gcf() - - -def test_super_chart(): - figure = _prep_chart_figure() - chart = chart_figure_to_chart(figure) - assert chart - - assert isinstance(chart, SuperChart) - assert chart.type == ChartType.SUPERCHART - assert chart.title == "Multiple Charts Example" - - charts = chart.elements - assert len(charts) == 2 - - first_chart = charts[0] - assert first_chart.title == "Sine Wave" - assert isinstance(first_chart, LineChart) - assert first_chart.x_label is None - assert first_chart.y_label is None - assert len(first_chart.elements) == 1 - assert len(first_chart.elements[0].points) == 100 - - second_chart = charts[1] - assert second_chart.title == "Scatter Plot" - assert isinstance(second_chart, ScatterChart) - assert second_chart.x_label == "X" - assert second_chart.y_label == "Y" - assert len(second_chart.elements) == 1 - assert len(second_chart.elements[0].points) == 5 diff --git a/chart_data_extractor/tests/charts/test_unknown.py b/chart_data_extractor/tests/charts/test_unknown.py deleted file mode 100644 index 848afe98..00000000 --- a/chart_data_extractor/tests/charts/test_unknown.py +++ /dev/null @@ -1,37 +0,0 @@ -import matplotlib.pyplot as plt - -from e2b_charts import chart_figure_to_chart -from e2b_charts.charts import Chart, ChartType - - -def _prep_chart_figure(): - # Create a figure and an axis - fig, ax = plt.subplots() - - # Create data for two concentric circles - circle1 = plt.Circle((0, 0), 1, color="blue", fill=False, linewidth=2) - circle2 = plt.Circle((0, 0), 2, color="red", fill=False, linewidth=2) - - # Add the circles to the axes - ax.add_artist(circle1) - ax.add_artist(circle2) - - # Set grid - ax.grid(True) - - # Set title - plt.title("Two Concentric Circles") - - return plt.gcf() - - -def test_unknown_charts(): - figure = _prep_chart_figure() - chart = chart_figure_to_chart(figure) - assert chart - - assert isinstance(chart, Chart) - assert chart.type == ChartType.UNKNOWN - assert chart.title == "Two Concentric Circles" - - assert len(chart.elements) == 0 diff --git a/chart_data_extractor/tests/utils/test_detect_scale.py b/chart_data_extractor/tests/utils/test_detect_scale.py deleted file mode 100644 index 62eaaa64..00000000 --- a/chart_data_extractor/tests/utils/test_detect_scale.py +++ /dev/null @@ -1,24 +0,0 @@ -import datetime - -from matplotlib.dates import _SwitchableDateConverter - -from e2b_charts.charts.planar import PointChart - - -def test_detect_scale(): - datetime_converter = _SwitchableDateConverter() - scale = PointChart._detect_scale( - datetime_converter, "linear", 3 * [datetime.date.today()], ["1", "2", "3"] - ) - assert scale == "datetime" - - scale = PointChart._detect_scale(None, "linear", [1, 2, 3], ["1", "2", "3"]) - assert scale == "linear" - - scale = PointChart._detect_scale( - None, "linear", [0, 1, 2], ["First", "Second", "Third"] - ) - assert scale == "categorical" - - scale = PointChart._detect_scale(None, "log", [1, 10, 100], ["1", "10", "100"]) - assert scale == "log" diff --git a/chart_data_extractor/tests/utils/test_is_grid_line.py b/chart_data_extractor/tests/utils/test_is_grid_line.py deleted file mode 100644 index 02dcd2fe..00000000 --- a/chart_data_extractor/tests/utils/test_is_grid_line.py +++ /dev/null @@ -1,17 +0,0 @@ -from matplotlib.lines import Line2D - -from e2b_charts.utils.filtering import is_grid_line - - -def test_is_grid_line(): - not_a_grid_line = Line2D([1, 2], [2, 3]) - assert not is_grid_line(not_a_grid_line) - - horizontal_grid_line = Line2D([1, 2], [2, 2]) - assert is_grid_line(horizontal_grid_line) - - vertical_grid_line = Line2D([1, 1], [2, 3]) - assert is_grid_line(vertical_grid_line) - - long_line = Line2D([1, 1, 1, 1], [2, 3, 4, 5]) - assert not is_grid_line(long_line) diff --git a/chart_data_extractor/uv.lock b/chart_data_extractor/uv.lock deleted file mode 100644 index 89b7f4bd..00000000 --- a/chart_data_extractor/uv.lock +++ /dev/null @@ -1,889 +0,0 @@ -version = 1 -revision = 3 -requires-python = ">=3.10" - -[[package]] -name = "annotated-types" -version = "0.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5f/56/a8120250d128bed162cd73c76d45f6ef9991f3e068f62a8ee060afa3104a/annotated_types-0.8.0.tar.gz", hash = "sha256:13b2beaad985e05e2d6407ee4c4f35590b11f8d693a258a561055cac8f64cab7", size = 15893, upload-time = "2026-07-23T20:16:13.995Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl", hash = "sha256:f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0", size = 13427, upload-time = "2026-07-23T20:16:12.938Z" }, -] - -[[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, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "contourpy" -version = "1.3.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130, upload-time = "2025-04-15T17:47:53.79Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/12/a3/da4153ec8fe25d263aa48c1a4cbde7f49b59af86f0b6f7862788c60da737/contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934", size = 268551, upload-time = "2025-04-15T17:34:46.581Z" }, - { url = "https://files.pythonhosted.org/packages/2f/6c/330de89ae1087eb622bfca0177d32a7ece50c3ef07b28002de4757d9d875/contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989", size = 253399, upload-time = "2025-04-15T17:34:51.427Z" }, - { url = "https://files.pythonhosted.org/packages/c1/bd/20c6726b1b7f81a8bee5271bed5c165f0a8e1f572578a9d27e2ccb763cb2/contourpy-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d", size = 312061, upload-time = "2025-04-15T17:34:55.961Z" }, - { url = "https://files.pythonhosted.org/packages/22/fc/a9665c88f8a2473f823cf1ec601de9e5375050f1958cbb356cdf06ef1ab6/contourpy-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9", size = 351956, upload-time = "2025-04-15T17:35:00.992Z" }, - { url = "https://files.pythonhosted.org/packages/25/eb/9f0a0238f305ad8fb7ef42481020d6e20cf15e46be99a1fcf939546a177e/contourpy-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512", size = 320872, upload-time = "2025-04-15T17:35:06.177Z" }, - { url = "https://files.pythonhosted.org/packages/32/5c/1ee32d1c7956923202f00cf8d2a14a62ed7517bdc0ee1e55301227fc273c/contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631", size = 325027, upload-time = "2025-04-15T17:35:11.244Z" }, - { url = "https://files.pythonhosted.org/packages/83/bf/9baed89785ba743ef329c2b07fd0611d12bfecbedbdd3eeecf929d8d3b52/contourpy-1.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f", size = 1306641, upload-time = "2025-04-15T17:35:26.701Z" }, - { url = "https://files.pythonhosted.org/packages/d4/cc/74e5e83d1e35de2d28bd97033426b450bc4fd96e092a1f7a63dc7369b55d/contourpy-1.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2", size = 1374075, upload-time = "2025-04-15T17:35:43.204Z" }, - { url = "https://files.pythonhosted.org/packages/0c/42/17f3b798fd5e033b46a16f8d9fcb39f1aba051307f5ebf441bad1ecf78f8/contourpy-1.3.2-cp310-cp310-win32.whl", hash = "sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0", size = 177534, upload-time = "2025-04-15T17:35:46.554Z" }, - { url = "https://files.pythonhosted.org/packages/54/ec/5162b8582f2c994721018d0c9ece9dc6ff769d298a8ac6b6a652c307e7df/contourpy-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a", size = 221188, upload-time = "2025-04-15T17:35:50.064Z" }, - { url = "https://files.pythonhosted.org/packages/b3/b9/ede788a0b56fc5b071639d06c33cb893f68b1178938f3425debebe2dab78/contourpy-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a37a2fb93d4df3fc4c0e363ea4d16f83195fc09c891bc8ce072b9d084853445", size = 269636, upload-time = "2025-04-15T17:35:54.473Z" }, - { url = "https://files.pythonhosted.org/packages/e6/75/3469f011d64b8bbfa04f709bfc23e1dd71be54d05b1b083be9f5b22750d1/contourpy-1.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b7cd50c38f500bbcc9b6a46643a40e0913673f869315d8e70de0438817cb7773", size = 254636, upload-time = "2025-04-15T17:35:58.283Z" }, - { url = "https://files.pythonhosted.org/packages/8d/2f/95adb8dae08ce0ebca4fd8e7ad653159565d9739128b2d5977806656fcd2/contourpy-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6658ccc7251a4433eebd89ed2672c2ed96fba367fd25ca9512aa92a4b46c4f1", size = 313053, upload-time = "2025-04-15T17:36:03.235Z" }, - { url = "https://files.pythonhosted.org/packages/c3/a6/8ccf97a50f31adfa36917707fe39c9a0cbc24b3bbb58185577f119736cc9/contourpy-1.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:70771a461aaeb335df14deb6c97439973d253ae70660ca085eec25241137ef43", size = 352985, upload-time = "2025-04-15T17:36:08.275Z" }, - { url = "https://files.pythonhosted.org/packages/1d/b6/7925ab9b77386143f39d9c3243fdd101621b4532eb126743201160ffa7e6/contourpy-1.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65a887a6e8c4cd0897507d814b14c54a8c2e2aa4ac9f7686292f9769fcf9a6ab", size = 323750, upload-time = "2025-04-15T17:36:13.29Z" }, - { url = "https://files.pythonhosted.org/packages/c2/f3/20c5d1ef4f4748e52d60771b8560cf00b69d5c6368b5c2e9311bcfa2a08b/contourpy-1.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3859783aefa2b8355697f16642695a5b9792e7a46ab86da1118a4a23a51a33d7", size = 326246, upload-time = "2025-04-15T17:36:18.329Z" }, - { url = "https://files.pythonhosted.org/packages/8c/e5/9dae809e7e0b2d9d70c52b3d24cba134dd3dad979eb3e5e71f5df22ed1f5/contourpy-1.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eab0f6db315fa4d70f1d8ab514e527f0366ec021ff853d7ed6a2d33605cf4b83", size = 1308728, upload-time = "2025-04-15T17:36:33.878Z" }, - { url = "https://files.pythonhosted.org/packages/e2/4a/0058ba34aeea35c0b442ae61a4f4d4ca84d6df8f91309bc2d43bb8dd248f/contourpy-1.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d91a3ccc7fea94ca0acab82ceb77f396d50a1f67412efe4c526f5d20264e6ecd", size = 1375762, upload-time = "2025-04-15T17:36:51.295Z" }, - { url = "https://files.pythonhosted.org/packages/09/33/7174bdfc8b7767ef2c08ed81244762d93d5c579336fc0b51ca57b33d1b80/contourpy-1.3.2-cp311-cp311-win32.whl", hash = "sha256:1c48188778d4d2f3d48e4643fb15d8608b1d01e4b4d6b0548d9b336c28fc9b6f", size = 178196, upload-time = "2025-04-15T17:36:55.002Z" }, - { url = "https://files.pythonhosted.org/packages/5e/fe/4029038b4e1c4485cef18e480b0e2cd2d755448bb071eb9977caac80b77b/contourpy-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:5ebac872ba09cb8f2131c46b8739a7ff71de28a24c869bcad554477eb089a878", size = 222017, upload-time = "2025-04-15T17:36:58.576Z" }, - { url = "https://files.pythonhosted.org/packages/34/f7/44785876384eff370c251d58fd65f6ad7f39adce4a093c934d4a67a7c6b6/contourpy-1.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4caf2bcd2969402bf77edc4cb6034c7dd7c0803213b3523f111eb7460a51b8d2", size = 271580, upload-time = "2025-04-15T17:37:03.105Z" }, - { url = "https://files.pythonhosted.org/packages/93/3b/0004767622a9826ea3d95f0e9d98cd8729015768075d61f9fea8eeca42a8/contourpy-1.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82199cb78276249796419fe36b7386bd8d2cc3f28b3bc19fe2454fe2e26c4c15", size = 255530, upload-time = "2025-04-15T17:37:07.026Z" }, - { url = "https://files.pythonhosted.org/packages/e7/bb/7bd49e1f4fa805772d9fd130e0d375554ebc771ed7172f48dfcd4ca61549/contourpy-1.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92", size = 307688, upload-time = "2025-04-15T17:37:11.481Z" }, - { url = "https://files.pythonhosted.org/packages/fc/97/e1d5dbbfa170725ef78357a9a0edc996b09ae4af170927ba8ce977e60a5f/contourpy-1.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d14f12932a8d620e307f715857107b1d1845cc44fdb5da2bc8e850f5ceba9f87", size = 347331, upload-time = "2025-04-15T17:37:18.212Z" }, - { url = "https://files.pythonhosted.org/packages/6f/66/e69e6e904f5ecf6901be3dd16e7e54d41b6ec6ae3405a535286d4418ffb4/contourpy-1.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:532fd26e715560721bb0d5fc7610fce279b3699b018600ab999d1be895b09415", size = 318963, upload-time = "2025-04-15T17:37:22.76Z" }, - { url = "https://files.pythonhosted.org/packages/a8/32/b8a1c8965e4f72482ff2d1ac2cd670ce0b542f203c8e1d34e7c3e6925da7/contourpy-1.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b383144cf2d2c29f01a1e8170f50dacf0eac02d64139dcd709a8ac4eb3cfe", size = 323681, upload-time = "2025-04-15T17:37:33.001Z" }, - { url = "https://files.pythonhosted.org/packages/30/c6/12a7e6811d08757c7162a541ca4c5c6a34c0f4e98ef2b338791093518e40/contourpy-1.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c49f73e61f1f774650a55d221803b101d966ca0c5a2d6d5e4320ec3997489441", size = 1308674, upload-time = "2025-04-15T17:37:48.64Z" }, - { url = "https://files.pythonhosted.org/packages/2a/8a/bebe5a3f68b484d3a2b8ffaf84704b3e343ef1addea528132ef148e22b3b/contourpy-1.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d80b2c0300583228ac98d0a927a1ba6a2ba6b8a742463c564f1d419ee5b211e", size = 1380480, upload-time = "2025-04-15T17:38:06.7Z" }, - { url = "https://files.pythonhosted.org/packages/34/db/fcd325f19b5978fb509a7d55e06d99f5f856294c1991097534360b307cf1/contourpy-1.3.2-cp312-cp312-win32.whl", hash = "sha256:90df94c89a91b7362e1142cbee7568f86514412ab8a2c0d0fca72d7e91b62912", size = 178489, upload-time = "2025-04-15T17:38:10.338Z" }, - { url = "https://files.pythonhosted.org/packages/01/c8/fadd0b92ffa7b5eb5949bf340a63a4a496a6930a6c37a7ba0f12acb076d6/contourpy-1.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:8c942a01d9163e2e5cfb05cb66110121b8d07ad438a17f9e766317bcb62abf73", size = 223042, upload-time = "2025-04-15T17:38:14.239Z" }, - { url = "https://files.pythonhosted.org/packages/2e/61/5673f7e364b31e4e7ef6f61a4b5121c5f170f941895912f773d95270f3a2/contourpy-1.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:de39db2604ae755316cb5967728f4bea92685884b1e767b7c24e983ef5f771cb", size = 271630, upload-time = "2025-04-15T17:38:19.142Z" }, - { url = "https://files.pythonhosted.org/packages/ff/66/a40badddd1223822c95798c55292844b7e871e50f6bfd9f158cb25e0bd39/contourpy-1.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3f9e896f447c5c8618f1edb2bafa9a4030f22a575ec418ad70611450720b5b08", size = 255670, upload-time = "2025-04-15T17:38:23.688Z" }, - { url = "https://files.pythonhosted.org/packages/1e/c7/cf9fdee8200805c9bc3b148f49cb9482a4e3ea2719e772602a425c9b09f8/contourpy-1.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71e2bd4a1c4188f5c2b8d274da78faab884b59df20df63c34f74aa1813c4427c", size = 306694, upload-time = "2025-04-15T17:38:28.238Z" }, - { url = "https://files.pythonhosted.org/packages/dd/e7/ccb9bec80e1ba121efbffad7f38021021cda5be87532ec16fd96533bb2e0/contourpy-1.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de425af81b6cea33101ae95ece1f696af39446db9682a0b56daaa48cfc29f38f", size = 345986, upload-time = "2025-04-15T17:38:33.502Z" }, - { url = "https://files.pythonhosted.org/packages/dc/49/ca13bb2da90391fa4219fdb23b078d6065ada886658ac7818e5441448b78/contourpy-1.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:977e98a0e0480d3fe292246417239d2d45435904afd6d7332d8455981c408b85", size = 318060, upload-time = "2025-04-15T17:38:38.672Z" }, - { url = "https://files.pythonhosted.org/packages/c8/65/5245ce8c548a8422236c13ffcdcdada6a2a812c361e9e0c70548bb40b661/contourpy-1.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:434f0adf84911c924519d2b08fc10491dd282b20bdd3fa8f60fd816ea0b48841", size = 322747, upload-time = "2025-04-15T17:38:43.712Z" }, - { url = "https://files.pythonhosted.org/packages/72/30/669b8eb48e0a01c660ead3752a25b44fdb2e5ebc13a55782f639170772f9/contourpy-1.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c66c4906cdbc50e9cba65978823e6e00b45682eb09adbb78c9775b74eb222422", size = 1308895, upload-time = "2025-04-15T17:39:00.224Z" }, - { url = "https://files.pythonhosted.org/packages/05/5a/b569f4250decee6e8d54498be7bdf29021a4c256e77fe8138c8319ef8eb3/contourpy-1.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8b7fc0cd78ba2f4695fd0a6ad81a19e7e3ab825c31b577f384aa9d7817dc3bef", size = 1379098, upload-time = "2025-04-15T17:43:29.649Z" }, - { url = "https://files.pythonhosted.org/packages/19/ba/b227c3886d120e60e41b28740ac3617b2f2b971b9f601c835661194579f1/contourpy-1.3.2-cp313-cp313-win32.whl", hash = "sha256:15ce6ab60957ca74cff444fe66d9045c1fd3e92c8936894ebd1f3eef2fff075f", size = 178535, upload-time = "2025-04-15T17:44:44.532Z" }, - { url = "https://files.pythonhosted.org/packages/12/6e/2fed56cd47ca739b43e892707ae9a13790a486a3173be063681ca67d2262/contourpy-1.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e1578f7eafce927b168752ed7e22646dad6cd9bca673c60bff55889fa236ebf9", size = 223096, upload-time = "2025-04-15T17:44:48.194Z" }, - { url = "https://files.pythonhosted.org/packages/54/4c/e76fe2a03014a7c767d79ea35c86a747e9325537a8b7627e0e5b3ba266b4/contourpy-1.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0475b1f6604896bc7c53bb070e355e9321e1bc0d381735421a2d2068ec56531f", size = 285090, upload-time = "2025-04-15T17:43:34.084Z" }, - { url = "https://files.pythonhosted.org/packages/7b/e2/5aba47debd55d668e00baf9651b721e7733975dc9fc27264a62b0dd26eb8/contourpy-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c85bb486e9be652314bb5b9e2e3b0d1b2e643d5eec4992c0fbe8ac71775da739", size = 268643, upload-time = "2025-04-15T17:43:38.626Z" }, - { url = "https://files.pythonhosted.org/packages/a1/37/cd45f1f051fe6230f751cc5cdd2728bb3a203f5619510ef11e732109593c/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:745b57db7758f3ffc05a10254edd3182a2a83402a89c00957a8e8a22f5582823", size = 310443, upload-time = "2025-04-15T17:43:44.522Z" }, - { url = "https://files.pythonhosted.org/packages/8b/a2/36ea6140c306c9ff6dd38e3bcec80b3b018474ef4d17eb68ceecd26675f4/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:970e9173dbd7eba9b4e01aab19215a48ee5dd3f43cef736eebde064a171f89a5", size = 349865, upload-time = "2025-04-15T17:43:49.545Z" }, - { url = "https://files.pythonhosted.org/packages/95/b7/2fc76bc539693180488f7b6cc518da7acbbb9e3b931fd9280504128bf956/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6c4639a9c22230276b7bffb6a850dfc8258a2521305e1faefe804d006b2e532", size = 321162, upload-time = "2025-04-15T17:43:54.203Z" }, - { url = "https://files.pythonhosted.org/packages/f4/10/76d4f778458b0aa83f96e59d65ece72a060bacb20cfbee46cf6cd5ceba41/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc829960f34ba36aad4302e78eabf3ef16a3a100863f0d4eeddf30e8a485a03b", size = 327355, upload-time = "2025-04-15T17:44:01.025Z" }, - { url = "https://files.pythonhosted.org/packages/43/a3/10cf483ea683f9f8ab096c24bad3cce20e0d1dd9a4baa0e2093c1c962d9d/contourpy-1.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d32530b534e986374fc19eaa77fcb87e8a99e5431499949b828312bdcd20ac52", size = 1307935, upload-time = "2025-04-15T17:44:17.322Z" }, - { url = "https://files.pythonhosted.org/packages/78/73/69dd9a024444489e22d86108e7b913f3528f56cfc312b5c5727a44188471/contourpy-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e298e7e70cf4eb179cc1077be1c725b5fd131ebc81181bf0c03525c8abc297fd", size = 1372168, upload-time = "2025-04-15T17:44:33.43Z" }, - { url = "https://files.pythonhosted.org/packages/0f/1b/96d586ccf1b1a9d2004dd519b25fbf104a11589abfd05484ff12199cca21/contourpy-1.3.2-cp313-cp313t-win32.whl", hash = "sha256:d0e589ae0d55204991450bb5c23f571c64fe43adaa53f93fc902a84c96f52fe1", size = 189550, upload-time = "2025-04-15T17:44:37.092Z" }, - { url = "https://files.pythonhosted.org/packages/b0/e6/6000d0094e8a5e32ad62591c8609e269febb6e4db83a1c75ff8868b42731/contourpy-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:78e9253c3de756b3f6a5174d024c4835acd59eb3f8e2ca13e775dbffe1558f69", size = 238214, upload-time = "2025-04-15T17:44:40.827Z" }, - { url = "https://files.pythonhosted.org/packages/33/05/b26e3c6ecc05f349ee0013f0bb850a761016d89cec528a98193a48c34033/contourpy-1.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c", size = 265681, upload-time = "2025-04-15T17:44:59.314Z" }, - { url = "https://files.pythonhosted.org/packages/2b/25/ac07d6ad12affa7d1ffed11b77417d0a6308170f44ff20fa1d5aa6333f03/contourpy-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16", size = 315101, upload-time = "2025-04-15T17:45:04.165Z" }, - { url = "https://files.pythonhosted.org/packages/8f/4d/5bb3192bbe9d3f27e3061a6a8e7733c9120e203cb8515767d30973f71030/contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad", size = 220599, upload-time = "2025-04-15T17:45:08.456Z" }, - { url = "https://files.pythonhosted.org/packages/ff/c0/91f1215d0d9f9f343e4773ba6c9b89e8c0cc7a64a6263f21139da639d848/contourpy-1.3.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5f5964cdad279256c084b69c3f412b7801e15356b16efa9d78aa974041903da0", size = 266807, upload-time = "2025-04-15T17:45:15.535Z" }, - { url = "https://files.pythonhosted.org/packages/d4/79/6be7e90c955c0487e7712660d6cead01fa17bff98e0ea275737cc2bc8e71/contourpy-1.3.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49b65a95d642d4efa8f64ba12558fcb83407e58a2dfba9d796d77b63ccfcaff5", size = 318729, upload-time = "2025-04-15T17:45:20.166Z" }, - { url = "https://files.pythonhosted.org/packages/87/68/7f46fb537958e87427d98a4074bcde4b67a70b04900cfc5ce29bc2f556c1/contourpy-1.3.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8c5acb8dddb0752bf252e01a3035b21443158910ac16a3b0d20e7fed7d534ce5", size = 221791, upload-time = "2025-04-15T17:45:24.794Z" }, -] - -[[package]] -name = "cycler" -version = "0.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, -] - -[[package]] -name = "e2b-charts" -version = "1.0.0" -source = { editable = "." } -dependencies = [ - { name = "matplotlib" }, - { name = "numpy" }, - { name = "pydantic" }, -] - -[package.dev-dependencies] -dev = [ - { name = "pytest" }, - { name = "pytest-dotenv" }, - { name = "python-dotenv" }, - { name = "ruff" }, -] - -[package.metadata] -requires-dist = [ - { name = "matplotlib", specifier = ">=3.10.3,<4" }, - { name = "numpy", specifier = ">=2.2.6,<3" }, - { name = "pydantic", specifier = ">=2.9.1,<3" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=9.0.3,<10" }, - { name = "pytest-dotenv", specifier = ">=0.5.2,<0.6" }, - { name = "python-dotenv", specifier = ">=1.2.1,<2" }, - { name = "ruff", specifier = ">=0.11.12,<0.12" }, -] - -[[package]] -name = "exceptiongroup" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, -] - -[[package]] -name = "fonttools" -version = "4.63.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/84/69/c97f2c18e0db87d2c7b15da1974dace76ae938f1cfa22e2727a648b7ed43/fonttools-4.63.0.tar.gz", hash = "sha256:caeb583deeb5168e694b65cda8b4ee62abedfa66cf88488734466f2366b9c4e0", size = 3597189, upload-time = "2026-05-14T12:04:30.958Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f2/c9/4141c90a90db20f807c7e10bfd689fe53eb8f7f4caff58ee4d4dfe46919f/fonttools-4.63.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e3297a6a4059b4acc3a1e9a8b04741f240a80044eef08ebd32e8b5bcdddce75b", size = 2884632, upload-time = "2026-05-14T12:02:38.56Z" }, - { url = "https://files.pythonhosted.org/packages/b8/46/ad12b5c10eae602d7ef814b02afa08aacbf89da917fed5b071282b7eadc2/fonttools-4.63.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b1cd75a03ad8cb5bc40c90bfde68c0c47de423aa19e5c0f362b43520645eea94", size = 2429441, upload-time = "2026-05-14T12:02:41.162Z" }, - { url = "https://files.pythonhosted.org/packages/90/8f/bdca24a84c81d56fffed052229cdcff368f6e05882e526f4558891481f65/fonttools-4.63.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0425b277a59cff3d80ca42162a8de360f318438a2ac83570842a678d826d579", size = 4946346, upload-time = "2026-05-14T12:02:43.41Z" }, - { url = "https://files.pythonhosted.org/packages/04/59/a639c0e136441ee91a65b56fdf89e5d075927e7a09c559d1b0f5276577db/fonttools-4.63.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d7e5c9973aa04c95650c96e5f5ad865fbf42d62079163ecfab1e01cbc2504c22", size = 4903184, upload-time = "2026-05-14T12:02:45.742Z" }, - { url = "https://files.pythonhosted.org/packages/e6/53/91b7e0cb45b536f3da1b29ba8cbab89f27e8b986809e0b1982303a3f4eca/fonttools-4.63.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cb014d58140a38135f16064c74c652ed57aa0b75cbf8bb59cac821f7edb5334e", size = 4922967, upload-time = "2026-05-14T12:02:48.386Z" }, - { url = "https://files.pythonhosted.org/packages/c7/b7/87439bf44e6b97c5538cd29d0b7e366a5b8ce2cc132a4134fb67fa3f2fa2/fonttools-4.63.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:032038247a96c1690f9f31e377c389383c902531b085aa4e4dabd6f57f870e69", size = 5042799, upload-time = "2026-05-14T12:02:50.424Z" }, - { url = "https://files.pythonhosted.org/packages/ad/7c/8b96c3263b89ef99cded544c0f0636686f85dbd3c211c4dceef0231fca23/fonttools-4.63.0-cp310-cp310-win32.whl", hash = "sha256:a8b33a82979e0a6a34ff435cc81317be1f95ec1ebb7a3a2d1c8a6a54f02ae44e", size = 1519704, upload-time = "2026-05-14T12:02:52.523Z" }, - { url = "https://files.pythonhosted.org/packages/e5/4d/2c2f0069970b6907de8fb5b05c5c0193cc22f717df151d1c7aef1c738f58/fonttools-4.63.0-cp310-cp310-win_amd64.whl", hash = "sha256:0c18358a155d75034911c5ee397a5b44cd19dd325dbb8b35fb60bf421d6a72ac", size = 1568666, upload-time = "2026-05-14T12:02:54.917Z" }, - { url = "https://files.pythonhosted.org/packages/75/2b/a7f1545bdf5da69c4bda0cea2a5781f0ad2a6623e0277267672db43c5fe6/fonttools-4.63.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2b8ae05d9eacf6081414d759c0a352769ac28ce31280d6bb8e77b03f9e3c449f", size = 2881793, upload-time = "2026-05-14T12:02:56.645Z" }, - { url = "https://files.pythonhosted.org/packages/49/50/965308c703f085f225db2886813b27e015b8b3438c350b22dd65b52c2a2c/fonttools-4.63.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79cdc9f567aec74a72918fd060283911406750cbc9fd28c1316023deb6ce31a9", size = 2428130, upload-time = "2026-05-14T12:02:58.891Z" }, - { url = "https://files.pythonhosted.org/packages/d8/38/6937fbd7f2dc3a6b48725851bc2c15ec949b9af14d9bbcb5fe83cdf9bdf9/fonttools-4.63.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c14b4fd138c4bafcca294765c547914e1aa431ae1ca94ab99d8db08c958bd3b", size = 5111952, upload-time = "2026-05-14T12:03:01.263Z" }, - { url = "https://files.pythonhosted.org/packages/0b/43/a81f20050a3115b57d62c8e781446949512eac36690dc384ccea65ff4cc1/fonttools-4.63.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76ac49f929aecaf82d83250b8347e099d7aecba0f4726c1d9b6df3b8bb5fe18", size = 5082308, upload-time = "2026-05-14T12:03:03.211Z" }, - { url = "https://files.pythonhosted.org/packages/67/00/cdd9d4944ca6ae280d01e69cc37bde3bf663630b837a6fc6d2cd65d80e0e/fonttools-4.63.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dcf076a4474fe0d7367e5bbf5b052c7284fa1feca729c04176ce513521afd8a0", size = 5087932, upload-time = "2026-05-14T12:03:05.147Z" }, - { url = "https://files.pythonhosted.org/packages/f5/f1/0aa0dbea778c75adbef223c42019fd47d22262b905974d62d829545d485f/fonttools-4.63.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7dd683fef0663e9f0f45cf541d788d24caa3ec9db50796b588e1757d8b3bc007", size = 5213271, upload-time = "2026-05-14T12:03:07.238Z" }, - { url = "https://files.pythonhosted.org/packages/a8/99/253e4056e1f0e67b9390125a154b73b5eb73ad521bece95c004858fdeec2/fonttools-4.63.0-cp311-cp311-win32.whl", hash = "sha256:afefc1ed0a59785a7fb06ea7e1678e849c193e1e387db783579bc7b3056fcfcb", size = 2304473, upload-time = "2026-05-14T12:03:09.271Z" }, - { url = "https://files.pythonhosted.org/packages/08/60/defa5e69641db890a63be281f41345f4c33b157824eaf0b9fad3e08b0dcb/fonttools-4.63.0-cp311-cp311-win_amd64.whl", hash = "sha256:063e08bd17bd5a90127a14123de0d6a952dbc847695fd98b63c043d58057f90c", size = 2356389, upload-time = "2026-05-14T12:03:11.53Z" }, - { url = "https://files.pythonhosted.org/packages/08/ef/b3c6b9b5be2f82416d73fe2ed2e96e2793cd80e7510bd6a17ca79cdd88ec/fonttools-4.63.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:37dd23e621e3b0aef1baa70a303b80aaf38449632cfc8fd2a55fb285bbccfc02", size = 2881131, upload-time = "2026-05-14T12:03:13.386Z" }, - { url = "https://files.pythonhosted.org/packages/44/a0/c815bea63117fa63e4e1c01f8a1110d2112fa003f838e6467094ec2432ce/fonttools-4.63.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a9faff9e0c1f76f9fd55899d2ce785832efebab37eb8ae13995853aef178bef0", size = 2426704, upload-time = "2026-05-14T12:03:15.801Z" }, - { url = "https://files.pythonhosted.org/packages/44/04/0b91d8e916e92ad1fac9e4624760baf0fd5ff2ead614c2f68fb21373f03f/fonttools-4.63.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef3048ef05dbb552b89817713d9cac912e00d0fde4a3105c00d29e52e10c89af", size = 5044298, upload-time = "2026-05-14T12:03:18.085Z" }, - { url = "https://files.pythonhosted.org/packages/77/c7/2342da9830e3e9d4870305ca5d2091d2a83284f2953079b7bdd3b5e029d8/fonttools-4.63.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:58dc6bb86a78d782f00f9190ca02c119cf5bbe2807536e361e18d42019f877d8", size = 4999800, upload-time = "2026-05-14T12:03:20.161Z" }, - { url = "https://files.pythonhosted.org/packages/e6/6d/67fe16c48d7ce050979b33f47e0d28a318f02da030602e944c34f7a16ef3/fonttools-4.63.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee08ebfa58f6e1aeff5697ab9582105bb620008c1caafb681e4c557e7483027b", size = 4982666, upload-time = "2026-05-14T12:03:22.87Z" }, - { url = "https://files.pythonhosted.org/packages/f2/00/3bbab338c07c71fa56269953845e92c951a61457bbbb0f1022551ea266d9/fonttools-4.63.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:27fdc65af8da6f88b9c6121c47a464cbe359fcfff7ff6fc2d37a1f395d755b78", size = 5133598, upload-time = "2026-05-14T12:03:25.168Z" }, - { url = "https://files.pythonhosted.org/packages/62/f2/aa27c7f98db5b064883dadcc5283947e81e034de42e22a33675878d98b54/fonttools-4.63.0-cp312-cp312-win32.whl", hash = "sha256:af2fd1664d00a397d75f806985ddb36282091c2131a73a6485c23b4a34722263", size = 2292575, upload-time = "2026-05-14T12:03:27.496Z" }, - { url = "https://files.pythonhosted.org/packages/87/36/cccb9bc2a6ab63d1b2980374f0dca72ce95ae267c9b4cfe77455bb70d0d4/fonttools-4.63.0-cp312-cp312-win_amd64.whl", hash = "sha256:59ac449f8cca9b4ffa08d2e7bbadad87ce710d69d1eda5c3c1ce579baa987272", size = 2343211, upload-time = "2026-05-14T12:03:30.057Z" }, - { url = "https://files.pythonhosted.org/packages/0f/8d/d8fec3dcde2963f8c908fb315e5ff2cd0ac34f82394bbbf73a2aa5145ce3/fonttools-4.63.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:cd7e9857e5e63738b9d9fd707bc1f59c8b09e5177726d23664db393c59bb08bd", size = 2876062, upload-time = "2026-05-14T12:03:32.554Z" }, - { url = "https://files.pythonhosted.org/packages/ef/71/d935dc54e4ff121bfdd11e08702db63a7e6f25af21d8a3d7b7212df53641/fonttools-4.63.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c2a2a42198b696a6f48fad91709afb55176e66a5e566131219dba372fb7f8c59", size = 2424594, upload-time = "2026-05-14T12:03:34.86Z" }, - { url = "https://files.pythonhosted.org/packages/8e/40/e76320afa1df918e146155ef239b1719ee266092e96f5423bfd075affba1/fonttools-4.63.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e874792a8212b44583ea02189d9e693906b2f78b261f372f95d6c563210ac1d", size = 5024840, upload-time = "2026-05-14T12:03:36.745Z" }, - { url = "https://files.pythonhosted.org/packages/ce/36/0b805d8c485f872f65a509cbe3b58a5d0d17bee855333b54a150c79d3061/fonttools-4.63.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22135da48a348785c5e2d5d2d9d6bec5ed44adacbaeb9db12d9493bf6c6bfa68", size = 4975801, upload-time = "2026-05-14T12:03:38.833Z" }, - { url = "https://files.pythonhosted.org/packages/c8/26/2cee03d0aa083ab022da5c07aff9ed3f689da1defb81ad6917c9627896da/fonttools-4.63.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ccf41f2efdf56994d22d73bef4ced1052161958169428d06ba9724ea9e9a64be", size = 4965009, upload-time = "2026-05-14T12:03:41.494Z" }, - { url = "https://files.pythonhosted.org/packages/7e/48/cc4b66d9058c0d0982c833fad10127c4b0e9324606aafa41382295ca4102/fonttools-4.63.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9ced0bd02ac751dd6319b0da88aaef24414e3b0dbc32bb4f24944821a3741a27", size = 5105892, upload-time = "2026-05-14T12:03:43.525Z" }, - { url = "https://files.pythonhosted.org/packages/d8/1f/a98a30a814b9ddef3a2e706025f90b9e0bc94890e6cb15254bc86547d11a/fonttools-4.63.0-cp313-cp313-win32.whl", hash = "sha256:85be818f5506e8a7753153def2c9550178f0ecae6a47b5e0e8dbb23f7cc90380", size = 2291313, upload-time = "2026-05-14T12:03:45.594Z" }, - { url = "https://files.pythonhosted.org/packages/92/46/5177b01f3b4abfdd4409f31cca4ab279c9343a26efbe9ec78c97fc612e02/fonttools-4.63.0-cp313-cp313-win_amd64.whl", hash = "sha256:ba04cb5891d4c0c21b6da95eda8d7b090021508a294fff33464fc7d241e0856b", size = 2342299, upload-time = "2026-05-14T12:03:47.414Z" }, - { url = "https://files.pythonhosted.org/packages/27/d2/23d25e3f247b328be58d04a4c9f894178a0d1eda7d42867cfb388adaf416/fonttools-4.63.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fd1e3094f42d806d3d7c79162fc59e5910fcbe3a7360c385b8da969bc4493745", size = 2875338, upload-time = "2026-05-14T12:03:50.052Z" }, - { url = "https://files.pythonhosted.org/packages/cd/58/7dfa0c761cb3b2964e2a84c4dc986c926a87de0cb9fb60d5b28ded3f2914/fonttools-4.63.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:6e528da43bc3791085f8cb6141b1d13e459226790240340fcbb4625649238b03", size = 2422661, upload-time = "2026-05-14T12:03:52.154Z" }, - { url = "https://files.pythonhosted.org/packages/dd/87/64cfa18a7a1621d17b7f4502b2b0ed8a135a90c3db51ea590ee99043e76b/fonttools-4.63.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b2248c5decb223562f7902ff6325077a073f608ee8e33e88ad88db734eb9f49", size = 5010526, upload-time = "2026-05-14T12:03:54.647Z" }, - { url = "https://files.pythonhosted.org/packages/36/e1/a8933a72c45a87177fbde2696e0d0755c8c9062f8c077a961c6215fa27b1/fonttools-4.63.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:308f957cdeaf8abe4e5f2f124902ef405448af92c90f80e302a3b771c2e6116b", size = 4923946, upload-time = "2026-05-14T12:03:56.984Z" }, - { url = "https://files.pythonhosted.org/packages/27/60/872e6e233b8c5e8b41413796ff18b7fe479661bd40147e071b450dfad7a1/fonttools-4.63.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bf00f21eb5fb721dbaf73d1e9da6d02a1af7768f2ebcf9798be98beab8ba90f6", size = 4962489, upload-time = "2026-05-14T12:03:59.443Z" }, - { url = "https://files.pythonhosted.org/packages/30/c4/83c24f2ec38b90cfda84bf4b1a1f49df80e84a1db4e7ac6e0d41bf23bc39/fonttools-4.63.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c1aaa4b9c75798400ac043ce04d74e7830376c85095a5a6ed7cba2f17a266bf4", size = 5071870, upload-time = "2026-05-14T12:04:02.122Z" }, - { url = "https://files.pythonhosted.org/packages/de/40/3ae22b60ff1d41ce0bd044b31238cdc72cef99f28b976f1e128ebd618c9b/fonttools-4.63.0-cp314-cp314-win32.whl", hash = "sha256:22693918177bd9ceabec4736d338045f357769416fc6b0b2508eefef75b08616", size = 2295026, upload-time = "2026-05-14T12:04:04.47Z" }, - { url = "https://files.pythonhosted.org/packages/c3/d4/98078064ccc76b45cb0f6c002452011e93c4bd26f6850344f0951cc1fe89/fonttools-4.63.0-cp314-cp314-win_amd64.whl", hash = "sha256:7d782fac32985914c351556f68ac0855391572bcd87de50e05970d3cd4c96fc5", size = 2347454, upload-time = "2026-05-14T12:04:06.752Z" }, - { url = "https://files.pythonhosted.org/packages/49/4e/652d1580c5f4e39f7d103b0c793e4773129ad633dce4addd0cf4dfebde02/fonttools-4.63.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:6db5140a60a5d731d21ec076745b40a310607731b0a565b50776393188649001", size = 2958152, upload-time = "2026-05-14T12:04:08.706Z" }, - { url = "https://files.pythonhosted.org/packages/0e/55/ad864c9a9b219f552eb46b32cd7906c466e5a578ba0c3abfcc0fe7413eb6/fonttools-4.63.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7d76edbff9014094dbf03bd2d074709dfa6ec7aba13d838c937a2b33d2d6a86e", size = 2460809, upload-time = "2026-05-14T12:04:10.783Z" }, - { url = "https://files.pythonhosted.org/packages/ea/2b/0aa8db70f18cf52e49b4ed5ecec68547f981160bf5ded3b5aed6faa0a6f9/fonttools-4.63.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0eac00b9118c3c2f87d272e45341871c5b3066baa3c86897fa634a7c3fb59096", size = 5148649, upload-time = "2026-05-14T12:04:12.747Z" }, - { url = "https://files.pythonhosted.org/packages/7f/63/18e4369c25043096f1048e0c9915951adc4f842bd81c6b18155824d6fa99/fonttools-4.63.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:51394295f1a51de8b5f30bdb1e1b9a4231536c7064ef5c6e211eec19fa36036f", size = 4932147, upload-time = "2026-05-14T12:04:14.806Z" }, - { url = "https://files.pythonhosted.org/packages/a1/3f/67f3eac2ffd8a98446c5022f8ed3864eac878a5ff7af8df4c8286dba16cc/fonttools-4.63.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9e12f105d2b6342c559c298afb674006bb2893afc7102dcf8a1b55b0486b4e40", size = 5027237, upload-time = "2026-05-14T12:04:17.675Z" }, - { url = "https://files.pythonhosted.org/packages/1a/ba/4e6214cb38a7b04779e97bb7636de9a5c7f20af7018d03dee0b64c08510a/fonttools-4.63.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:796f27556dbe094c4824f75ca85267e4df776c79036c8441469a4df37038c196", size = 5053933, upload-time = "2026-05-14T12:04:20.818Z" }, - { url = "https://files.pythonhosted.org/packages/34/3b/214dcc19ee31d3d38fb5ad2755c11ef0514e5dc300bbaf41c0b69f393799/fonttools-4.63.0-cp314-cp314t-win32.whl", hash = "sha256:948428a275741f0b64b113c955425a953314f4b9ab9997f73a72c83e68e569c8", size = 2359326, upload-time = "2026-05-14T12:04:24.22Z" }, - { url = "https://files.pythonhosted.org/packages/dd/1e/3ff1a9b523058c2eeb6a9d50f5574e2a738200d0d94107d5bc4105e8da3f/fonttools-4.63.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6d4741eb179121cab9eea4cb2393d24492373a260d7945006358c08cfbf45419", size = 2425829, upload-time = "2026-05-14T12:04:26.829Z" }, - { url = "https://files.pythonhosted.org/packages/2c/47/c99d5268f354002ce80f8d029cd9d7d872969da1de8b93d32de4dc56d6f4/fonttools-4.63.0-py3-none-any.whl", hash = "sha256:445af2eab030a16b9171ea8bdda7ebf7d96bda2df88ee182a464252f6e05e20d", size = 1164562, upload-time = "2026-05-14T12:04:29.092Z" }, -] - -[[package]] -name = "iniconfig" -version = "2.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, -] - -[[package]] -name = "kiwisolver" -version = "1.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", size = 103482, upload-time = "2026-03-09T13:15:53.382Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ac/f8/06549565caa026e540b7e7bab5c5a90eb7ca986015f4c48dace243cd24d9/kiwisolver-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:32cc0a5365239a6ea0c6ed461e8838d053b57e397443c0ca894dcc8e388d4374", size = 122802, upload-time = "2026-03-09T13:12:37.515Z" }, - { url = "https://files.pythonhosted.org/packages/84/eb/8476a0818850c563ff343ea7c9c05dcdcbd689a38e01aa31657df01f91fa/kiwisolver-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cc0b66c1eec9021353a4b4483afb12dfd50e3669ffbb9152d6842eb34c7e29fd", size = 66216, upload-time = "2026-03-09T13:12:38.812Z" }, - { url = "https://files.pythonhosted.org/packages/f3/c4/f9c8a6b4c21aed4198566e45923512986d6cef530e7263b3a5f823546561/kiwisolver-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:86e0287879f75621ae85197b0877ed2f8b7aa57b511c7331dce2eb6f4de7d476", size = 63917, upload-time = "2026-03-09T13:12:40.053Z" }, - { url = "https://files.pythonhosted.org/packages/f1/0e/ba4ae25d03722f64de8b2c13e80d82ab537a06b30fc7065183c6439357e3/kiwisolver-1.5.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:62f59da443c4f4849f73a51a193b1d9d258dcad0c41bc4d1b8fb2bcc04bfeb22", size = 1628776, upload-time = "2026-03-09T13:12:41.976Z" }, - { url = "https://files.pythonhosted.org/packages/8a/e4/3f43a011bc8a0860d1c96f84d32fa87439d3feedf66e672fef03bf5e8bac/kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9190426b7aa26c5229501fa297b8d0653cfd3f5a36f7990c264e157cbf886b3b", size = 1228164, upload-time = "2026-03-09T13:12:44.002Z" }, - { url = "https://files.pythonhosted.org/packages/4b/34/3a901559a1e0c218404f9a61a93be82d45cb8f44453ba43088644980f033/kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c8277104ded0a51e699c8c3aff63ce2c56d4ed5519a5f73e0fd7057f959a2b9e", size = 1246656, upload-time = "2026-03-09T13:12:45.557Z" }, - { url = "https://files.pythonhosted.org/packages/87/9e/f78c466ea20527822b95ad38f141f2de1dcd7f23fb8716b002b0d91bbe59/kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8f9baf6f0a6e7571c45c8863010b45e837c3ee1c2c77fcd6ef423be91b21fedb", size = 1295562, upload-time = "2026-03-09T13:12:47.562Z" }, - { url = "https://files.pythonhosted.org/packages/0a/66/fd0e4a612e3a286c24e6d6f3a5428d11258ed1909bc530ba3b59807fd980/kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cff8e5383db4989311f99e814feeb90c4723eb4edca425b9d5d9c3fefcdd9537", size = 2178473, upload-time = "2026-03-09T13:12:50.254Z" }, - { url = "https://files.pythonhosted.org/packages/dc/8e/6cac929e0049539e5ee25c1ee937556f379ba5204840d03008363ced662d/kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ebae99ed6764f2b5771c522477b311be313e8841d2e0376db2b10922daebbba4", size = 2274035, upload-time = "2026-03-09T13:12:51.785Z" }, - { url = "https://files.pythonhosted.org/packages/ca/d3/9d0c18f1b52ea8074b792452cf17f1f5a56bd0302a85191f405cfbf9da16/kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:d5cd5189fc2b6a538b75ae45433140c4823463918f7b1617c31e68b085c0022c", size = 2443217, upload-time = "2026-03-09T13:12:53.329Z" }, - { url = "https://files.pythonhosted.org/packages/45/2a/6e19368803a038b2a90857bf4ee9e3c7b667216d045866bf22d3439fd75e/kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f42c23db5d1521218a3276bb08666dcb662896a0be7347cba864eca45ff64ede", size = 2249196, upload-time = "2026-03-09T13:12:55.057Z" }, - { url = "https://files.pythonhosted.org/packages/75/2b/3f641dfcbe72e222175d626bacf2f72c3b34312afec949dd1c50afa400f5/kiwisolver-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:94eff26096eb5395136634622515b234ecb6c9979824c1f5004c6e3c3c85ccd2", size = 73389, upload-time = "2026-03-09T13:12:56.496Z" }, - { url = "https://files.pythonhosted.org/packages/da/88/299b137b9e0025d8982e03d2d52c123b0a2b159e84b0ef1501ef446339cf/kiwisolver-1.5.0-cp310-cp310-win_arm64.whl", hash = "sha256:dd952e03bfbb096cfe2dd35cd9e00f269969b67536cb4370994afc20ff2d0875", size = 64782, upload-time = "2026-03-09T13:12:57.609Z" }, - { url = "https://files.pythonhosted.org/packages/12/dd/a495a9c104be1c476f0386e714252caf2b7eca883915422a64c50b88c6f5/kiwisolver-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9eed0f7edbb274413b6ee781cca50541c8c0facd3d6fd289779e494340a2b85c", size = 122798, upload-time = "2026-03-09T13:12:58.963Z" }, - { url = "https://files.pythonhosted.org/packages/11/60/37b4047a2af0cf5ef6d8b4b26e91829ae6fc6a2d1f74524bcb0e7cd28a32/kiwisolver-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c4923e404d6bcd91b6779c009542e5647fef32e4a5d75e115e3bbac6f2335eb", size = 66216, upload-time = "2026-03-09T13:13:00.155Z" }, - { url = "https://files.pythonhosted.org/packages/0a/aa/510dc933d87767584abfe03efa445889996c70c2990f6f87c3ebaa0a18c5/kiwisolver-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0df54df7e686afa55e6f21fb86195224a6d9beb71d637e8d7920c95cf0f89aac", size = 63911, upload-time = "2026-03-09T13:13:01.671Z" }, - { url = "https://files.pythonhosted.org/packages/80/46/bddc13df6c2a40741e0cc7865bb1c9ed4796b6760bd04ce5fae3928ef917/kiwisolver-1.5.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2517e24d7315eb51c10664cdb865195df38ab74456c677df67bb47f12d088a27", size = 1438209, upload-time = "2026-03-09T13:13:03.385Z" }, - { url = "https://files.pythonhosted.org/packages/fd/d6/76621246f5165e5372f02f5e6f3f48ea336a8f9e96e43997d45b240ed8cd/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff710414307fefa903e0d9bdf300972f892c23477829f49504e59834f4195398", size = 1248888, upload-time = "2026-03-09T13:13:05.231Z" }, - { url = "https://files.pythonhosted.org/packages/b2/c1/31559ec6fb39a5b48035ce29bb63ade628f321785f38c384dee3e2c08bc1/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6176c1811d9d5a04fa391c490cc44f451e240697a16977f11c6f722efb9041db", size = 1266304, upload-time = "2026-03-09T13:13:06.743Z" }, - { url = "https://files.pythonhosted.org/packages/5e/ef/1cb8276f2d29cc6a41e0a042f27946ca347d3a4a75acf85d0a16aa6dcc82/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50847dca5d197fcbd389c805aa1a1cf32f25d2e7273dc47ab181a517666b68cc", size = 1319650, upload-time = "2026-03-09T13:13:08.607Z" }, - { url = "https://files.pythonhosted.org/packages/4c/e4/5ba3cecd7ce6236ae4a80f67e5d5531287337d0e1f076ca87a5abe4cd5d0/kiwisolver-1.5.0-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:01808c6d15f4c3e8559595d6d1fe6411c68e4a3822b4b9972b44473b24f4e679", size = 970949, upload-time = "2026-03-09T13:13:10.299Z" }, - { url = "https://files.pythonhosted.org/packages/5a/69/dc61f7ae9a2f071f26004ced87f078235b5507ab6e5acd78f40365655034/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f1f9f4121ec58628c96baa3de1a55a4e3a333c5102c8e94b64e23bf7b2083309", size = 2199125, upload-time = "2026-03-09T13:13:11.841Z" }, - { url = "https://files.pythonhosted.org/packages/e5/7b/abbe0f1b5afa85f8d084b73e90e5f801c0939eba16ac2e49af7c61a6c28d/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b7d335370ae48a780c6e6a6bbfa97342f563744c39c35562f3f367665f5c1de2", size = 2293783, upload-time = "2026-03-09T13:13:14.399Z" }, - { url = "https://files.pythonhosted.org/packages/8a/80/5908ae149d96d81580d604c7f8aefd0e98f4fd728cf172f477e9f2a81744/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:800ee55980c18545af444d93fdd60c56b580db5cc54867d8cbf8a1dc0829938c", size = 1960726, upload-time = "2026-03-09T13:13:16.047Z" }, - { url = "https://files.pythonhosted.org/packages/84/08/a78cb776f8c085b7143142ce479859cfec086bd09ee638a317040b6ef420/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c438f6ca858697c9ab67eb28246c92508af972e114cac34e57a6d4ba17a3ac08", size = 2464738, upload-time = "2026-03-09T13:13:17.897Z" }, - { url = "https://files.pythonhosted.org/packages/b1/e1/65584da5356ed6cb12c63791a10b208860ac40a83de165cb6a6751a686e3/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8c63c91f95173f9c2a67c7c526b2cea976828a0e7fced9cdcead2802dc10f8a4", size = 2270718, upload-time = "2026-03-09T13:13:19.421Z" }, - { url = "https://files.pythonhosted.org/packages/be/6c/28f17390b62b8f2f520e2915095b3c94d88681ecf0041e75389d9667f202/kiwisolver-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:beb7f344487cdcb9e1efe4b7a29681b74d34c08f0043a327a74da852a6749e7b", size = 73480, upload-time = "2026-03-09T13:13:20.818Z" }, - { url = "https://files.pythonhosted.org/packages/d8/0e/2ee5debc4f77a625778fec5501ff3e8036fe361b7ee28ae402a485bb9694/kiwisolver-1.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:ad4ae4ffd1ee9cd11357b4c66b612da9888f4f4daf2f36995eda64bd45370cac", size = 64930, upload-time = "2026-03-09T13:13:21.997Z" }, - { url = "https://files.pythonhosted.org/packages/4d/b2/818b74ebea34dabe6d0c51cb1c572e046730e64844da6ed646d5298c40ce/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4e9750bc21b886308024f8a54ccb9a2cc38ac9fa813bf4348434e3d54f337ff9", size = 123158, upload-time = "2026-03-09T13:13:23.127Z" }, - { url = "https://files.pythonhosted.org/packages/bf/d9/405320f8077e8e1c5c4bd6adc45e1e6edf6d727b6da7f2e2533cf58bff71/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72ec46b7eba5b395e0a7b63025490d3214c11013f4aacb4f5e8d6c3041829588", size = 66388, upload-time = "2026-03-09T13:13:24.765Z" }, - { url = "https://files.pythonhosted.org/packages/99/9f/795fedf35634f746151ca8839d05681ceb6287fbed6cc1c9bf235f7887c2/kiwisolver-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ed3a984b31da7481b103f68776f7128a89ef26ed40f4dc41a2223cda7fb24819", size = 64068, upload-time = "2026-03-09T13:13:25.878Z" }, - { url = "https://files.pythonhosted.org/packages/c4/13/680c54afe3e65767bed7ec1a15571e1a2f1257128733851ade24abcefbcc/kiwisolver-1.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb5136fb5352d3f422df33f0c879a1b0c204004324150cc3b5e3c4f310c9049f", size = 1477934, upload-time = "2026-03-09T13:13:27.166Z" }, - { url = "https://files.pythonhosted.org/packages/c8/2f/cebfcdb60fd6a9b0f6b47a9337198bcbad6fbe15e68189b7011fd914911f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2af221f268f5af85e776a73d62b0845fc8baf8ef0abfae79d29c77d0e776aaf", size = 1278537, upload-time = "2026-03-09T13:13:28.707Z" }, - { url = "https://files.pythonhosted.org/packages/f2/0d/9b782923aada3fafb1d6b84e13121954515c669b18af0c26e7d21f579855/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b0f172dc8ffaccb8522d7c5d899de00133f2f1ca7b0a49b7da98e901de87bf2d", size = 1296685, upload-time = "2026-03-09T13:13:30.528Z" }, - { url = "https://files.pythonhosted.org/packages/27/70/83241b6634b04fe44e892688d5208332bde130f38e610c0418f9ede47ded/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6ab8ba9152203feec73758dad83af9a0bbe05001eb4639e547207c40cfb52083", size = 1346024, upload-time = "2026-03-09T13:13:32.818Z" }, - { url = "https://files.pythonhosted.org/packages/e4/db/30ed226fb271ae1a6431fc0fe0edffb2efe23cadb01e798caeb9f2ceae8f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:cdee07c4d7f6d72008d3f73b9bf027f4e11550224c7c50d8df1ae4a37c1402a6", size = 987241, upload-time = "2026-03-09T13:13:34.435Z" }, - { url = "https://files.pythonhosted.org/packages/ec/bd/c314595208e4c9587652d50959ead9e461995389664e490f4dce7ff0f782/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7c60d3c9b06fb23bd9c6139281ccbdc384297579ae037f08ae90c69f6845c0b1", size = 2227742, upload-time = "2026-03-09T13:13:36.4Z" }, - { url = "https://files.pythonhosted.org/packages/c1/43/0499cec932d935229b5543d073c2b87c9c22846aab48881e9d8d6e742a2d/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e315e5ec90d88e140f57696ff85b484ff68bb311e36f2c414aa4286293e6dee0", size = 2323966, upload-time = "2026-03-09T13:13:38.204Z" }, - { url = "https://files.pythonhosted.org/packages/3d/6f/79b0d760907965acfd9d61826a3d41f8f093c538f55cd2633d3f0db269f6/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:1465387ac63576c3e125e5337a6892b9e99e0627d52317f3ca79e6930d889d15", size = 1977417, upload-time = "2026-03-09T13:13:39.966Z" }, - { url = "https://files.pythonhosted.org/packages/ab/31/01d0537c41cb75a551a438c3c7a80d0c60d60b81f694dac83dd436aec0d0/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:530a3fd64c87cffa844d4b6b9768774763d9caa299e9b75d8eca6a4423b31314", size = 2491238, upload-time = "2026-03-09T13:13:41.698Z" }, - { url = "https://files.pythonhosted.org/packages/e4/34/8aefdd0be9cfd00a44509251ba864f5caf2991e36772e61c408007e7f417/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1d9daea4ea6b9be74fe2f01f7fbade8d6ffab263e781274cffca0dba9be9eec9", size = 2294947, upload-time = "2026-03-09T13:13:43.343Z" }, - { url = "https://files.pythonhosted.org/packages/ad/cf/0348374369ca588f8fe9c338fae49fa4e16eeb10ffb3d012f23a54578a9e/kiwisolver-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:f18c2d9782259a6dc132fdc7a63c168cbc74b35284b6d75c673958982a378384", size = 73569, upload-time = "2026-03-09T13:13:45.792Z" }, - { url = "https://files.pythonhosted.org/packages/28/26/192b26196e2316e2bd29deef67e37cdf9870d9af8e085e521afff0fed526/kiwisolver-1.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:f7c7553b13f69c1b29a5bde08ddc6d9d0c8bfb84f9ed01c30db25944aeb852a7", size = 64997, upload-time = "2026-03-09T13:13:46.878Z" }, - { url = "https://files.pythonhosted.org/packages/9d/69/024d6711d5ba575aa65d5538042e99964104e97fa153a9f10bc369182bc2/kiwisolver-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:fd40bb9cd0891c4c3cb1ddf83f8bbfa15731a248fdc8162669405451e2724b09", size = 123166, upload-time = "2026-03-09T13:13:48.032Z" }, - { url = "https://files.pythonhosted.org/packages/ce/48/adbb40df306f587054a348831220812b9b1d787aff714cfbc8556e38fccd/kiwisolver-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c0e1403fd7c26d77c1f03e096dc58a5c726503fa0db0456678b8668f76f521e3", size = 66395, upload-time = "2026-03-09T13:13:49.365Z" }, - { url = "https://files.pythonhosted.org/packages/a8/3a/d0a972b34e1c63e2409413104216cd1caa02c5a37cb668d1687d466c1c45/kiwisolver-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dda366d548e89a90d88a86c692377d18d8bd64b39c1fb2b92cb31370e2896bbd", size = 64065, upload-time = "2026-03-09T13:13:50.562Z" }, - { url = "https://files.pythonhosted.org/packages/2b/0a/7b98e1e119878a27ba8618ca1e18b14f992ff1eda40f47bccccf4de44121/kiwisolver-1.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:332b4f0145c30b5f5ad9374881133e5aa64320428a57c2c2b61e9d891a51c2f3", size = 1477903, upload-time = "2026-03-09T13:13:52.084Z" }, - { url = "https://files.pythonhosted.org/packages/18/d8/55638d89ffd27799d5cc3d8aa28e12f4ce7a64d67b285114dbedc8ea4136/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c50b89ffd3e1a911c69a1dd3de7173c0cd10b130f56222e57898683841e4f96", size = 1278751, upload-time = "2026-03-09T13:13:54.673Z" }, - { url = "https://files.pythonhosted.org/packages/b8/97/b4c8d0d18421ecceba20ad8701358453b88e32414e6f6950b5a4bad54e65/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4db576bb8c3ef9365f8b40fe0f671644de6736ae2c27a2c62d7d8a1b4329f099", size = 1296793, upload-time = "2026-03-09T13:13:56.287Z" }, - { url = "https://files.pythonhosted.org/packages/c4/10/f862f94b6389d8957448ec9df59450b81bec4abb318805375c401a1e6892/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0b85aad90cea8ac6797a53b5d5f2e967334fa4d1149f031c4537569972596cb8", size = 1346041, upload-time = "2026-03-09T13:13:58.269Z" }, - { url = "https://files.pythonhosted.org/packages/a3/6a/f1650af35821eaf09de398ec0bc2aefc8f211f0cda50204c9f1673741ba9/kiwisolver-1.5.0-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:d36ca54cb4c6c4686f7cbb7b817f66f5911c12ddb519450bbe86707155028f87", size = 987292, upload-time = "2026-03-09T13:13:59.871Z" }, - { url = "https://files.pythonhosted.org/packages/de/19/d7fb82984b9238115fe629c915007be608ebd23dc8629703d917dbfaffd4/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:38f4a703656f493b0ad185211ccfca7f0386120f022066b018eb5296d8613e23", size = 2227865, upload-time = "2026-03-09T13:14:01.401Z" }, - { url = "https://files.pythonhosted.org/packages/7f/b9/46b7f386589fd222dac9e9de9c956ce5bcefe2ee73b4e79891381dda8654/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3ac2360e93cb41be81121755c6462cff3beaa9967188c866e5fce5cf13170859", size = 2324369, upload-time = "2026-03-09T13:14:02.972Z" }, - { url = "https://files.pythonhosted.org/packages/92/8b/95e237cf3d9c642960153c769ddcbe278f182c8affb20cecc1cc983e7cc5/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c95cab08d1965db3d84a121f1c7ce7479bdd4072c9b3dafd8fecce48a2e6b902", size = 1977989, upload-time = "2026-03-09T13:14:04.503Z" }, - { url = "https://files.pythonhosted.org/packages/1b/95/980c9df53501892784997820136c01f62bc1865e31b82b9560f980c0e649/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fc20894c3d21194d8041a28b65622d5b86db786da6e3cfe73f0c762951a61167", size = 2491645, upload-time = "2026-03-09T13:14:06.106Z" }, - { url = "https://files.pythonhosted.org/packages/cb/32/900647fd0840abebe1561792c6b31e6a7c0e278fc3973d30572a965ca14c/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7a32f72973f0f950c1920475d5c5ea3d971b81b6f0ec53b8d0a956cc965f22e0", size = 2295237, upload-time = "2026-03-09T13:14:08.891Z" }, - { url = "https://files.pythonhosted.org/packages/be/8a/be60e3bbcf513cc5a50f4a3e88e1dcecebb79c1ad607a7222877becaa101/kiwisolver-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bf3acf1419fa93064a4c2189ac0b58e3be7872bf6ee6177b0d4c63dc4cea276", size = 73573, upload-time = "2026-03-09T13:14:12.327Z" }, - { url = "https://files.pythonhosted.org/packages/4d/d2/64be2e429eb4fca7f7e1c52a91b12663aeaf25de3895e5cca0f47ef2a8d0/kiwisolver-1.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:fa8eb9ecdb7efb0b226acec134e0d709e87a909fa4971a54c0c4f6e88635484c", size = 64998, upload-time = "2026-03-09T13:14:13.469Z" }, - { url = "https://files.pythonhosted.org/packages/b0/69/ce68dd0c85755ae2de490bf015b62f2cea5f6b14ff00a463f9d0774449ff/kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:db485b3847d182b908b483b2ed133c66d88d49cacf98fd278fadafe11b4478d1", size = 125700, upload-time = "2026-03-09T13:14:14.636Z" }, - { url = "https://files.pythonhosted.org/packages/74/aa/937aac021cf9d4349990d47eb319309a51355ed1dbdc9c077cdc9224cb11/kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:be12f931839a3bdfe28b584db0e640a65a8bcbc24560ae3fdb025a449b3d754e", size = 67537, upload-time = "2026-03-09T13:14:15.808Z" }, - { url = "https://files.pythonhosted.org/packages/ee/20/3a87fbece2c40ad0f6f0aefa93542559159c5f99831d596050e8afae7a9f/kiwisolver-1.5.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:16b85d37c2cbb3253226d26e64663f755d88a03439a9c47df6246b35defbdfb7", size = 65514, upload-time = "2026-03-09T13:14:18.035Z" }, - { url = "https://files.pythonhosted.org/packages/f0/7f/f943879cda9007c45e1f7dba216d705c3a18d6b35830e488b6c6a4e7cdf0/kiwisolver-1.5.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4432b835675f0ea7414aab3d37d119f7226d24869b7a829caeab49ebda407b0c", size = 1584848, upload-time = "2026-03-09T13:14:19.745Z" }, - { url = "https://files.pythonhosted.org/packages/37/f8/4d4f85cc1870c127c88d950913370dd76138482161cd07eabbc450deff01/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b0feb50971481a2cc44d94e88bdb02cdd497618252ae226b8eb1201b957e368", size = 1391542, upload-time = "2026-03-09T13:14:21.54Z" }, - { url = "https://files.pythonhosted.org/packages/04/0b/65dd2916c84d252b244bd405303220f729e7c17c9d7d33dca6feeff9ffc4/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56fa888f10d0f367155e76ce849fa1166fc9730d13bd2d65a2aa13b6f5424489", size = 1404447, upload-time = "2026-03-09T13:14:23.205Z" }, - { url = "https://files.pythonhosted.org/packages/39/5c/2606a373247babce9b1d056c03a04b65f3cf5290a8eac5d7bdead0a17e21/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:940dda65d5e764406b9fb92761cbf462e4e63f712ab60ed98f70552e496f3bf1", size = 1455918, upload-time = "2026-03-09T13:14:24.74Z" }, - { url = "https://files.pythonhosted.org/packages/d5/d1/c6078b5756670658e9192a2ef11e939c92918833d2745f85cd14a6004bdf/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_39_riscv64.whl", hash = "sha256:89fc958c702ee9a745e4700378f5d23fddbc46ff89e8fdbf5395c24d5c1452a3", size = 1072856, upload-time = "2026-03-09T13:14:26.597Z" }, - { url = "https://files.pythonhosted.org/packages/cb/c8/7def6ddf16eb2b3741d8b172bdaa9af882b03c78e9b0772975408801fa63/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9027d773c4ff81487181a925945743413f6069634d0b122d0b37684ccf4f1e18", size = 2333580, upload-time = "2026-03-09T13:14:28.237Z" }, - { url = "https://files.pythonhosted.org/packages/9e/87/2ac1fce0eb1e616fcd3c35caa23e665e9b1948bb984f4764790924594128/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:5b233ea3e165e43e35dba1d2b8ecc21cf070b45b65ae17dd2747d2713d942021", size = 2423018, upload-time = "2026-03-09T13:14:30.018Z" }, - { url = "https://files.pythonhosted.org/packages/67/13/c6700ccc6cc218716bfcda4935e4b2997039869b4ad8a94f364c5a3b8e63/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ce9bf03dad3b46408c08649c6fbd6ca28a9fce0eb32fdfffa6775a13103b5310", size = 2062804, upload-time = "2026-03-09T13:14:32.888Z" }, - { url = "https://files.pythonhosted.org/packages/1b/bd/877056304626943ff0f1f44c08f584300c199b887cb3176cd7e34f1515f1/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:fc4d3f1fb9ca0ae9f97b095963bc6326f1dbfd3779d6679a1e016b9baaa153d3", size = 2597482, upload-time = "2026-03-09T13:14:34.971Z" }, - { url = "https://files.pythonhosted.org/packages/75/19/c60626c47bf0f8ac5dcf72c6c98e266d714f2fbbfd50cf6dab5ede3aaa50/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f443b4825c50a51ee68585522ab4a1d1257fac65896f282b4c6763337ac9f5d2", size = 2394328, upload-time = "2026-03-09T13:14:36.816Z" }, - { url = "https://files.pythonhosted.org/packages/47/84/6a6d5e5bb8273756c27b7d810d47f7ef2f1f9b9fd23c9ee9a3f8c75c9cef/kiwisolver-1.5.0-cp313-cp313t-win_arm64.whl", hash = "sha256:893ff3a711d1b515ba9da14ee090519bad4610ed1962fbe298a434e8c5f8db53", size = 68410, upload-time = "2026-03-09T13:14:38.695Z" }, - { url = "https://files.pythonhosted.org/packages/e4/d7/060f45052f2a01ad5762c8fdecd6d7a752b43400dc29ff75cd47225a40fd/kiwisolver-1.5.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8df31fe574b8b3993cc61764f40941111b25c2d9fea13d3ce24a49907cd2d615", size = 123231, upload-time = "2026-03-09T13:14:41.323Z" }, - { url = "https://files.pythonhosted.org/packages/c2/a7/78da680eadd06ff35edef6ef68a1ad273bad3e2a0936c9a885103230aece/kiwisolver-1.5.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1d49a49ac4cbfb7c1375301cd1ec90169dfeae55ff84710d782260ce77a75a02", size = 66489, upload-time = "2026-03-09T13:14:42.534Z" }, - { url = "https://files.pythonhosted.org/packages/49/b2/97980f3ad4fae37dd7fe31626e2bf75fbf8bdf5d303950ec1fab39a12da8/kiwisolver-1.5.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0cbe94b69b819209a62cb27bdfa5dc2a8977d8de2f89dfd97ba4f53ed3af754e", size = 64063, upload-time = "2026-03-09T13:14:44.759Z" }, - { url = "https://files.pythonhosted.org/packages/e7/f9/b06c934a6aa8bc91f566bd2a214fd04c30506c2d9e2b6b171953216a65b6/kiwisolver-1.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:80aa065ffd378ff784822a6d7c3212f2d5f5e9c3589614b5c228b311fd3063ac", size = 1475913, upload-time = "2026-03-09T13:14:46.247Z" }, - { url = "https://files.pythonhosted.org/packages/6b/f0/f768ae564a710135630672981231320bc403cf9152b5596ec5289de0f106/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e7f886f47ab881692f278ae901039a234e4025a68e6dfab514263a0b1c4ae05", size = 1282782, upload-time = "2026-03-09T13:14:48.458Z" }, - { url = "https://files.pythonhosted.org/packages/e2/9f/1de7aad00697325f05238a5f2eafbd487fb637cc27a558b5367a5f37fb7f/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5060731cc3ed12ca3a8b57acd4aeca5bbc2f49216dd0bec1650a1acd89486bcd", size = 1300815, upload-time = "2026-03-09T13:14:50.721Z" }, - { url = "https://files.pythonhosted.org/packages/5a/c2/297f25141d2e468e0ce7f7a7b92e0cf8918143a0cbd3422c1ad627e85a06/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a4aa69609f40fce3cbc3f87b2061f042eee32f94b8f11db707b66a26461591a", size = 1347925, upload-time = "2026-03-09T13:14:52.304Z" }, - { url = "https://files.pythonhosted.org/packages/b9/d3/f4c73a02eb41520c47610207b21afa8cdd18fdbf64ffd94674ae21c4812d/kiwisolver-1.5.0-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:d168fda2dbff7b9b5f38e693182d792a938c31db4dac3a80a4888de603c99554", size = 991322, upload-time = "2026-03-09T13:14:54.637Z" }, - { url = "https://files.pythonhosted.org/packages/7b/46/d3f2efef7732fcda98d22bf4ad5d3d71d545167a852ca710a494f4c15343/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:413b820229730d358efd838ecbab79902fe97094565fdc80ddb6b0a18c18a581", size = 2232857, upload-time = "2026-03-09T13:14:56.471Z" }, - { url = "https://files.pythonhosted.org/packages/3f/ec/2d9756bf2b6d26ae4349b8d3662fb3993f16d80c1f971c179ce862b9dbae/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5124d1ea754509b09e53738ec185584cc609aae4a3b510aaf4ed6aa047ef9303", size = 2329376, upload-time = "2026-03-09T13:14:58.072Z" }, - { url = "https://files.pythonhosted.org/packages/8f/9f/876a0a0f2260f1bde92e002b3019a5fabc35e0939c7d945e0fa66185eb20/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e4415a8db000bf49a6dd1c478bf70062eaacff0f462b92b0ba68791a905861f9", size = 1982549, upload-time = "2026-03-09T13:14:59.668Z" }, - { url = "https://files.pythonhosted.org/packages/6c/4f/ba3624dfac23a64d54ac4179832860cb537c1b0af06024936e82ca4154a0/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d618fd27420381a4f6044faa71f46d8bfd911bd077c555f7138ed88729bfbe79", size = 2494680, upload-time = "2026-03-09T13:15:01.364Z" }, - { url = "https://files.pythonhosted.org/packages/39/b7/97716b190ab98911b20d10bf92eca469121ec483b8ce0edd314f51bc85af/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5092eb5b1172947f57d6ea7d89b2f29650414e4293c47707eb499ec07a0ac796", size = 2297905, upload-time = "2026-03-09T13:15:03.925Z" }, - { url = "https://files.pythonhosted.org/packages/a3/36/4e551e8aa55c9188bca9abb5096805edbf7431072b76e2298e34fd3a3008/kiwisolver-1.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:d76e2d8c75051d58177e762164d2e9ab92886534e3a12e795f103524f221dd8e", size = 75086, upload-time = "2026-03-09T13:15:07.775Z" }, - { url = "https://files.pythonhosted.org/packages/70/15/9b90f7df0e31a003c71649cf66ef61c3c1b862f48c81007fa2383c8bd8d7/kiwisolver-1.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:fa6248cd194edff41d7ea9425ced8ca3a6f838bfb295f6f1d6e6bb694a8518df", size = 66577, upload-time = "2026-03-09T13:15:09.139Z" }, - { url = "https://files.pythonhosted.org/packages/17/01/7dc8c5443ff42b38e72731643ed7cf1ed9bf01691ae5cdca98501999ed83/kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:d1ffeb80b5676463d7a7d56acbe8e37a20ce725570e09549fe738e02ca6b7e1e", size = 125794, upload-time = "2026-03-09T13:15:10.525Z" }, - { url = "https://files.pythonhosted.org/packages/46/8a/b4ebe46ebaac6a303417fab10c2e165c557ddaff558f9699d302b256bc53/kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bc4d8e252f532ab46a1de9349e2d27b91fce46736a9eedaa37beaca66f574ed4", size = 67646, upload-time = "2026-03-09T13:15:12.016Z" }, - { url = "https://files.pythonhosted.org/packages/60/35/10a844afc5f19d6f567359bf4789e26661755a2f36200d5d1ed8ad0126e5/kiwisolver-1.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6783e069732715ad0c3ce96dbf21dbc2235ab0593f2baf6338101f70371f4028", size = 65511, upload-time = "2026-03-09T13:15:13.311Z" }, - { url = "https://files.pythonhosted.org/packages/f8/8a/685b297052dd041dcebce8e8787b58923b6e78acc6115a0dc9189011c44b/kiwisolver-1.5.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e7c4c09a490dc4d4a7f8cbee56c606a320f9dc28cf92a7157a39d1ce7676a657", size = 1584858, upload-time = "2026-03-09T13:15:15.103Z" }, - { url = "https://files.pythonhosted.org/packages/9e/80/04865e3d4638ac5bddec28908916df4a3075b8c6cc101786a96803188b96/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a075bd7bd19c70cf67c8badfa36cf7c5d8de3c9ddb8420c51e10d9c50e94920", size = 1392539, upload-time = "2026-03-09T13:15:16.661Z" }, - { url = "https://files.pythonhosted.org/packages/ba/01/77a19cacc0893fa13fafa46d1bba06fb4dc2360b3292baf4b56d8e067b24/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bdd3e53429ff02aa319ba59dfe4ceeec345bf46cf180ec2cf6fd5b942e7975e9", size = 1405310, upload-time = "2026-03-09T13:15:18.229Z" }, - { url = "https://files.pythonhosted.org/packages/53/39/bcaf5d0cca50e604cfa9b4e3ae1d64b50ca1ae5b754122396084599ef903/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cdcb35dc9d807259c981a85531048ede628eabcffb3239adf3d17463518992d", size = 1456244, upload-time = "2026-03-09T13:15:20.444Z" }, - { url = "https://files.pythonhosted.org/packages/d0/7a/72c187abc6975f6978c3e39b7cf67aeb8b3c0a8f9790aa7fd412855e9e1f/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:70d593af6a6ca332d1df73d519fddb5148edb15cd90d5f0155e3746a6d4fcc65", size = 1073154, upload-time = "2026-03-09T13:15:22.039Z" }, - { url = "https://files.pythonhosted.org/packages/c7/ca/cf5b25783ebbd59143b4371ed0c8428a278abe68d6d0104b01865b1bbd0f/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:377815a8616074cabbf3f53354e1d040c35815a134e01d7614b7692e4bf8acfa", size = 2334377, upload-time = "2026-03-09T13:15:23.741Z" }, - { url = "https://files.pythonhosted.org/packages/4a/e5/b1f492adc516796e88751282276745340e2a72dcd0d36cf7173e0daf3210/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0255a027391d52944eae1dbb5d4cc5903f57092f3674e8e544cdd2622826b3f0", size = 2425288, upload-time = "2026-03-09T13:15:25.789Z" }, - { url = "https://files.pythonhosted.org/packages/e6/e5/9b21fbe91a61b8f409d74a26498706e97a48008bfcd1864373d32a6ba31c/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:012b1eb16e28718fa782b5e61dc6f2da1f0792ca73bd05d54de6cb9561665fc9", size = 2063158, upload-time = "2026-03-09T13:15:27.63Z" }, - { url = "https://files.pythonhosted.org/packages/b1/02/83f47986138310f95ea95531f851b2a62227c11cbc3e690ae1374fe49f0f/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0e3aafb33aed7479377e5e9a82e9d4bf87063741fc99fc7ae48b0f16e32bdd6f", size = 2597260, upload-time = "2026-03-09T13:15:29.421Z" }, - { url = "https://files.pythonhosted.org/packages/07/18/43a5f24608d8c313dd189cf838c8e68d75b115567c6279de7796197cfb6a/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7a116ae737f0000343218c4edf5bd45893bfeaff0993c0b215d7124c9f77646", size = 2394403, upload-time = "2026-03-09T13:15:31.517Z" }, - { url = "https://files.pythonhosted.org/packages/3b/b5/98222136d839b8afabcaa943b09bd05888c2d36355b7e448550211d1fca4/kiwisolver-1.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:1dd9b0b119a350976a6d781e7278ec7aca0b201e1a9e2d23d9804afecb6ca681", size = 79687, upload-time = "2026-03-09T13:15:33.204Z" }, - { url = "https://files.pythonhosted.org/packages/99/a2/ca7dc962848040befed12732dff6acae7fb3c4f6fc4272b3f6c9a30b8713/kiwisolver-1.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:58f812017cd2985c21fbffb4864d59174d4903dd66fa23815e74bbc7a0e2dd57", size = 70032, upload-time = "2026-03-09T13:15:34.411Z" }, - { url = "https://files.pythonhosted.org/packages/1c/fa/2910df836372d8761bb6eff7d8bdcb1613b5c2e03f260efe7abe34d388a7/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_10_13_x86_64.whl", hash = "sha256:5ae8e62c147495b01a0f4765c878e9bfdf843412446a247e28df59936e99e797", size = 130262, upload-time = "2026-03-09T13:15:35.629Z" }, - { url = "https://files.pythonhosted.org/packages/0f/41/c5f71f9f00aabcc71fee8b7475e3f64747282580c2fe748961ba29b18385/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f6764a4ccab3078db14a632420930f6186058750df066b8ea2a7106df91d3203", size = 138036, upload-time = "2026-03-09T13:15:36.894Z" }, - { url = "https://files.pythonhosted.org/packages/fa/06/7399a607f434119c6e1fdc8ec89a8d51ccccadf3341dee4ead6bd14caaf5/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c31c13da98624f957b0fb1b5bae5383b2333c2c3f6793d9825dd5ce79b525cb7", size = 194295, upload-time = "2026-03-09T13:15:38.22Z" }, - { url = "https://files.pythonhosted.org/packages/b5/91/53255615acd2a1eaca307ede3c90eb550bae9c94581f8c00081b6b1c8f44/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:1f1489f769582498610e015a8ef2d36f28f505ab3096d0e16b4858a9ec214f57", size = 75987, upload-time = "2026-03-09T13:15:39.65Z" }, - { url = "https://files.pythonhosted.org/packages/17/6f/6fd4f690a40c2582fa34b97d2678f718acf3706b91d270c65ecb455d0a06/kiwisolver-1.5.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:295d9ffe712caa9f8a3081de8d32fc60191b4b51c76f02f951fd8407253528f4", size = 59606, upload-time = "2026-03-09T13:15:40.81Z" }, - { url = "https://files.pythonhosted.org/packages/82/a0/2355d5e3b338f13ce63f361abb181e3b6ea5fffdb73f739b3e80efa76159/kiwisolver-1.5.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:51e8c4084897de9f05898c2c2a39af6318044ae969d46ff7a34ed3f96274adca", size = 57537, upload-time = "2026-03-09T13:15:42.071Z" }, - { url = "https://files.pythonhosted.org/packages/c8/b9/1d50e610ecadebe205b71d6728fd224ce0e0ca6aba7b9cbe1da049203ac5/kiwisolver-1.5.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b83af57bdddef03c01a9138034c6ff03181a3028d9a1003b301eb1a55e161a3f", size = 79888, upload-time = "2026-03-09T13:15:43.317Z" }, - { url = "https://files.pythonhosted.org/packages/cd/ee/b85ffcd75afed0357d74f0e6fc02a4507da441165de1ca4760b9f496390d/kiwisolver-1.5.0-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf4679a3d71012a7c2bf360e5cd878fbd5e4fcac0896b56393dec239d81529ed", size = 77584, upload-time = "2026-03-09T13:15:44.605Z" }, - { url = "https://files.pythonhosted.org/packages/6b/dd/644d0dde6010a8583b4cd66dd41c5f83f5325464d15c4f490b3340ab73b4/kiwisolver-1.5.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:41024ed50e44ab1a60d3fe0a9d15a4ccc9f5f2b1d814ff283c8d01134d5b81bc", size = 73390, upload-time = "2026-03-09T13:15:45.832Z" }, - { url = "https://files.pythonhosted.org/packages/e9/eb/5fcbbbf9a0e2c3a35effb88831a483345326bbc3a030a3b5b69aee647f84/kiwisolver-1.5.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ec4c85dc4b687c7f7f15f553ff26a98bfe8c58f5f7f0ac8905f0ba4c7be60232", size = 59532, upload-time = "2026-03-09T13:15:47.047Z" }, - { url = "https://files.pythonhosted.org/packages/c3/9b/e17104555bb4db148fd52327feea1e96be4b88e8e008b029002c281a21ab/kiwisolver-1.5.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:12e91c215a96e39f57989c8912ae761286ac5a9584d04030ceb3368a357f017a", size = 57420, upload-time = "2026-03-09T13:15:48.199Z" }, - { url = "https://files.pythonhosted.org/packages/48/44/2b5b95b7aa39fb2d8d9d956e0f3d5d45aef2ae1d942d4c3ffac2f9cfed1a/kiwisolver-1.5.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:be4a51a55833dc29ab5d7503e7bcb3b3af3402d266018137127450005cdfe737", size = 79892, upload-time = "2026-03-09T13:15:49.694Z" }, - { url = "https://files.pythonhosted.org/packages/52/7d/7157f9bba6b455cfb4632ed411e199fc8b8977642c2b12082e1bd9e6d173/kiwisolver-1.5.0-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:daae526907e262de627d8f70058a0f64acc9e2641c164c99c8f594b34a799a16", size = 77603, upload-time = "2026-03-09T13:15:50.945Z" }, - { url = "https://files.pythonhosted.org/packages/0a/dd/8050c947d435c8d4bc94e3252f4d8bb8a76cfb424f043a8680be637a57f1/kiwisolver-1.5.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:59cd8683f575d96df5bb48f6add94afc055012c29e28124fcae2b63661b9efb1", size = 73558, upload-time = "2026-03-09T13:15:52.112Z" }, -] - -[[package]] -name = "matplotlib" -version = "3.10.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "contourpy" }, - { name = "cycler" }, - { name = "fonttools" }, - { name = "kiwisolver" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "pillow" }, - { name = "pyparsing" }, - { name = "python-dateutil" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/63/1b/4be5be87d43d327a0cf4de1a56e86f7f84c89312452406cf122efe2839e6/matplotlib-3.10.9.tar.gz", hash = "sha256:fd66508e8c6877d98e586654b608a0456db8d7e8a546eb1e2600efd957302358", size = 34811233, upload-time = "2026-04-24T00:14:13.539Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/18/6f/340b04986e67aac6f66c5145ce68bf72c64bed30f92c8913499a6e6b8f99/matplotlib-3.10.9-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77210dce9cb8153dffc967efaae990543392563d5a376d4dd8539bebcb0ed217", size = 8296625, upload-time = "2026-04-24T00:11:43.376Z" }, - { url = "https://files.pythonhosted.org/packages/bb/2f/127081eb83162053ebb9678ceac64220b93a663e0167432566e9c7c82aab/matplotlib-3.10.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1e7698ac9868428e84d2c967424803b2472ff7167d9d6590d4204ed775343c3b", size = 8188790, upload-time = "2026-04-24T00:11:46.556Z" }, - { url = "https://files.pythonhosted.org/packages/fc/b7/d8bcec2626c35f96972bff656299fef4578113ea6193c8fdad324710410c/matplotlib-3.10.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1aa972116abb4c9d201bf245620b433726cb6856f3bef6a78f776a00f5c92d37", size = 8769389, upload-time = "2026-04-24T00:11:48.959Z" }, - { url = "https://files.pythonhosted.org/packages/12/49/b78e214a527ea732033b7f4d37f7afb504d74ba9d134bd47938230dfb8b1/matplotlib-3.10.9-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae2f11957b27ce53497dd4d7b235c4d4f1faf383dfb39d0c5beb833bff883294", size = 9589657, upload-time = "2026-04-24T00:11:51.915Z" }, - { url = "https://files.pythonhosted.org/packages/5f/15/5246f7b43beae19c74dfee651d58d6cc8112e06f77adb4e88cc04f2e3a23/matplotlib-3.10.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b049278ddce116aaa1c1377ebf58adea909132dfce0281cf7e3a1ea9fc2e2c65", size = 9651983, upload-time = "2026-04-24T00:11:54.766Z" }, - { url = "https://files.pythonhosted.org/packages/75/77/5acecfe672ba0fa1b8c0454f69ce155d1e6fc5852fa7206bf9afaf767121/matplotlib-3.10.9-cp310-cp310-win_amd64.whl", hash = "sha256:82834c3c292d24d3a8aae77cd2d20019de69d692a34a970e4fdb8d33e2ea3dda", size = 8199701, upload-time = "2026-04-24T00:11:58.389Z" }, - { url = "https://files.pythonhosted.org/packages/4c/8c/290f021104741fea63769c31494f5324c0cd249bf536a65a4350767b1f22/matplotlib-3.10.9-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:68cfdcede415f7c8f5577b03303dd94526cdb6d11036cecdc205e08733b2d2bb", size = 8306860, upload-time = "2026-04-24T00:12:01.207Z" }, - { url = "https://files.pythonhosted.org/packages/51/18/325cd32ece1120d1da51cc4e4294c6580190699490183fc2fe8cb6d61ec5/matplotlib-3.10.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfca0129678bd56379db26c52b5d77ed7de314c047492fbdc763aa7501710cfb", size = 8199254, upload-time = "2026-04-24T00:12:04.239Z" }, - { url = "https://files.pythonhosted.org/packages/79/db/e28c1b83e3680740aa78925f5fb2ae4d16207207419ad75ea9fe604f8676/matplotlib-3.10.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e436d155fa8a3399dc62683f8f5d0e2e50d25d0144a73edd73f82eec8f4abfb", size = 8777092, upload-time = "2026-04-24T00:12:06.793Z" }, - { url = "https://files.pythonhosted.org/packages/55/fa/3ce7adfe9ba101748f465211660d9c6374c876b671bdb8c2bb6d347e8b94/matplotlib-3.10.9-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56fc0bd271b00025c6edfdc7c2dcd247372c8e1544971d62e1dc7c17367e8bf9", size = 9595691, upload-time = "2026-04-24T00:12:09.706Z" }, - { url = "https://files.pythonhosted.org/packages/36/c4/6960a76686ed668f2c60f84e9799ba4c0d56abdb36b1577b60c1d061d1ec/matplotlib-3.10.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a5a6104ed666402ba5106d7f36e0e0cdca4e8d7fa4d39708ca88019e2835a2eb", size = 9659771, upload-time = "2026-04-24T00:12:12.766Z" }, - { url = "https://files.pythonhosted.org/packages/7e/0d/271aace3342157c64700c9ff4c59c7b392f3dbab393692e8db6fbe7ab96c/matplotlib-3.10.9-cp311-cp311-win_amd64.whl", hash = "sha256:d730e984eddf56974c3e72b6129c7ca462ac38dc624338f4b0b23eb23ecba00f", size = 8205112, upload-time = "2026-04-24T00:12:15.773Z" }, - { url = "https://files.pythonhosted.org/packages/e2/ee/cb57ad4754f3e7b9174ce6ce66d9205fb827067e48a9f58ac09d7e7d6b77/matplotlib-3.10.9-cp311-cp311-win_arm64.whl", hash = "sha256:51bf0ddbdc598e060d46c16b5590708f81a1624cefbaaf62f6a81bf9285b8c80", size = 8132310, upload-time = "2026-04-24T00:12:18.645Z" }, - { url = "https://files.pythonhosted.org/packages/35/c6/5581e26c72233ebb2a2a6fed2d24fb7c66b4700120b813f51b0555acf0b6/matplotlib-3.10.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f0c3c28d9fbcc1fe7a03be236d73430cf6409c41fb2383a7ac52fe932b072cb1", size = 8319908, upload-time = "2026-04-24T00:12:21.323Z" }, - { url = "https://files.pythonhosted.org/packages/b7/18/4880dd762e40cd360c1bf06e890c5a97b997e91cb324602b1a19950ad5ce/matplotlib-3.10.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41cb28c2bd769aa3e98322c6ab09854cbcc52ab69d2759d681bba3e327b2b320", size = 8216016, upload-time = "2026-04-24T00:12:23.4Z" }, - { url = "https://files.pythonhosted.org/packages/32/91/d024616abdba99e83120e07a20658976f6a343646710760c4a51df126029/matplotlib-3.10.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ae20801130378b82d647ff5047c07316295b68dc054ca6b3c13519d0ea624285", size = 8789336, upload-time = "2026-04-24T00:12:26.096Z" }, - { url = "https://files.pythonhosted.org/packages/5c/04/030a2f61ef2158f5e4c259487a92ac877732499fb33d871585d89e03c42d/matplotlib-3.10.9-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6c63ebcd8b4b169eb2f5c200552ae6b8be8999a005b6b507ed76fb8d7d674fe2", size = 9604602, upload-time = "2026-04-24T00:12:29.052Z" }, - { url = "https://files.pythonhosted.org/packages/fc/c2/541e4d09d87bb6b5830fc28b4c887a9a8cf4e1c6cee698a8c05552ae2003/matplotlib-3.10.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d75d11c949914165976c621b2324f9ef162af7ebf4b057ddf95dd1dba7e5edcf", size = 9670966, upload-time = "2026-04-24T00:12:32.131Z" }, - { url = "https://files.pythonhosted.org/packages/04/a1/4571fc46e7702de8d0c2dc54ad1b2f8e29328dea3ee90831181f7353d93c/matplotlib-3.10.9-cp312-cp312-win_amd64.whl", hash = "sha256:d091f9d758b34aaaaa6331d13574bf01891d903b3dec59bfff458ef7551de5d6", size = 8217462, upload-time = "2026-04-24T00:12:35.226Z" }, - { url = "https://files.pythonhosted.org/packages/4b/d0/2269edb12aa30c13c8bcc9382892e39943ce1d28aab4ec296e0381798e81/matplotlib-3.10.9-cp312-cp312-win_arm64.whl", hash = "sha256:10cc5ce06d10231c36f40e875f3c7e8050362a4ee8f0ee5d29a6b3277d57bb42", size = 8136688, upload-time = "2026-04-24T00:12:37.442Z" }, - { url = "https://files.pythonhosted.org/packages/aa/d3/8d4f6afbecb49fc04e060a57c0fce39ea51cc163a6bd87303ccd698e4fa6/matplotlib-3.10.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b580440f1ff81a0e34122051a3dfabb7e4b7f9e380629929bde0eff9af72165f", size = 8320331, upload-time = "2026-04-24T00:12:39.688Z" }, - { url = "https://files.pythonhosted.org/packages/63/d9/9e14bc7564bf92d5ffa801ae5fac819ce74b925dfb55e3ebde61a3bbad3e/matplotlib-3.10.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b1b745c489cd1a77a0dc1120a05dc87af9798faebc913601feb8c73d89bf2d1e", size = 8216461, upload-time = "2026-04-24T00:12:42.494Z" }, - { url = "https://files.pythonhosted.org/packages/8a/17/4402d0d14ccf1dfc70932600b68097fbbf9c898a4871d2cbbe79c7801a32/matplotlib-3.10.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8f3bcac1ca5ed000a6f4337d47ba67dfddf37ed6a46c15fd7f014997f7bf865f", size = 8790091, upload-time = "2026-04-24T00:12:44.789Z" }, - { url = "https://files.pythonhosted.org/packages/3e/0b/322aeec06dd9b91411f92028b37d447342770a24392aa4813e317064dad5/matplotlib-3.10.9-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a8d66a55def891c33147ba3ba9bfcabf0b526a43764c818acbb4525e5ed0838", size = 9605027, upload-time = "2026-04-24T00:12:47.583Z" }, - { url = "https://files.pythonhosted.org/packages/74/88/5f13482f55e7b00bcfc09838b093c2456e1379978d2a146844aae05350ad/matplotlib-3.10.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d843374407c4017a6403b59c6c81606773d136f3259d5b6da3131bc814542cc2", size = 9671269, upload-time = "2026-04-24T00:12:50.878Z" }, - { url = "https://files.pythonhosted.org/packages/c5/e0/0840fd2f93da988ec660b8ad1984abe9f25d2aed22a5e394ff1c68c88307/matplotlib-3.10.9-cp313-cp313-win_amd64.whl", hash = "sha256:f4399f64b3e94cd500195490972ae1ee81170df1636fa15364d157d5bdd7b921", size = 8217588, upload-time = "2026-04-24T00:12:53.784Z" }, - { url = "https://files.pythonhosted.org/packages/47/b9/d706d06dd605c49b9f83a2aed8c13e3e5db70697d7a80b7e3d7915de6b17/matplotlib-3.10.9-cp313-cp313-win_arm64.whl", hash = "sha256:ba7b3b8ef09eab7df0e86e9ae086faa433efbfbdb46afcb3aa16aabf779469a8", size = 8136913, upload-time = "2026-04-24T00:12:56.501Z" }, - { url = "https://files.pythonhosted.org/packages/9b/45/6e32d96978264c8ca8c4b1010adb955a1a49cfaf314e212bbc8908f04a61/matplotlib-3.10.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:09218df8a93712bd6ea133e83a153c755448cf7868316c531cffcc43f69d1cc9", size = 8368019, upload-time = "2026-04-24T00:12:58.896Z" }, - { url = "https://files.pythonhosted.org/packages/86/0a/c8e3d3bba245f0f7fc424937f8ff7ef77291a36af3edb97ccd78aa93d84f/matplotlib-3.10.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:82368699727bfb7b0182e1aa13082e3c08e092fa1a25d3e1fd92405bff96f6d4", size = 8264645, upload-time = "2026-04-24T00:13:01.406Z" }, - { url = "https://files.pythonhosted.org/packages/3d/aa/5bf5a14fe4fed73a4209a155606f8096ff797aad89c6c35179026571133e/matplotlib-3.10.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3225f4e1edcb8c86c884ddf79ebe20ecd0a67d30188f279897554ccd8fded4dc", size = 8802194, upload-time = "2026-04-24T00:13:03.702Z" }, - { url = "https://files.pythonhosted.org/packages/dd/5e/b4be852d6bba6fd15893fadf91ff26ae49cb91aac789e95dde9d342e664f/matplotlib-3.10.9-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de2445a0c6690d21b7eb6ce071cebad6d40a2e9bdf10d039074a96ba19797b99", size = 9622684, upload-time = "2026-04-24T00:13:06.647Z" }, - { url = "https://files.pythonhosted.org/packages/4c/3d/ed428c971139112ef730f62770654d609467346d09d4b62617e1afd68a5a/matplotlib-3.10.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:b2b9516251cb89ff618d757daec0e2ed1bf21248013844a853d87ef85ab3081d", size = 9680790, upload-time = "2026-04-24T00:13:10.009Z" }, - { url = "https://files.pythonhosted.org/packages/e7/09/052e884aaf2b985c63cb79f715f1d5b6a3eaa7de78f6a52b9dbc077d5b53/matplotlib-3.10.9-cp313-cp313t-win_amd64.whl", hash = "sha256:e9fae004b941b23ff2edcf1567a857ed77bafc8086ffa258190462328434faf8", size = 8287571, upload-time = "2026-04-24T00:13:13.087Z" }, - { url = "https://files.pythonhosted.org/packages/f4/38/ae27288e788c35a4250491422f3db7750366fc8c97d6f36fbdecfc1f5518/matplotlib-3.10.9-cp313-cp313t-win_arm64.whl", hash = "sha256:6b63d9c7c769b88ab81e10dc86e4e0607cf56817b9f9e6cf24b2a5f1693b8e38", size = 8188292, upload-time = "2026-04-24T00:13:15.546Z" }, - { url = "https://files.pythonhosted.org/packages/d6/e6/3bd8afd04949f02eabc1c17115ea5255e19cacd4d06fc5abdde4eeb0052c/matplotlib-3.10.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:172db52c9e683f5d12eaf57f0f54834190e12581fe1cc2a19595a8f5acb4e77d", size = 8321276, upload-time = "2026-04-24T00:13:18.318Z" }, - { url = "https://files.pythonhosted.org/packages/41/86/86231232fff41c9f8e4a1a7d7a597d349a02527109c3af7d618366122139/matplotlib-3.10.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:97e35e8d39ccc85859095e01a53847432ba9a53ddf7986f7a54a11b73d0e143f", size = 8218218, upload-time = "2026-04-24T00:13:20.974Z" }, - { url = "https://files.pythonhosted.org/packages/85/8f/becc9722cafc64f5d2eb0b7c1bf5f585271c618a45dbd8fabeb021f898b6/matplotlib-3.10.9-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aba1615dabe83188e19d4f75a253c6a08423e04c1425e64039f800050a69de6b", size = 9608145, upload-time = "2026-04-24T00:13:23.228Z" }, - { url = "https://files.pythonhosted.org/packages/32/5d/f7e914f7d9325abff4057cee62c0fa70263683189f774473cbfb534cd13b/matplotlib-3.10.9-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34cf8167e023ad956c15f36302911d5406bd99a9862c1a8499ea6f7c0e015dc2", size = 9885085, upload-time = "2026-04-24T00:13:25.849Z" }, - { url = "https://files.pythonhosted.org/packages/a5/fd/fa69f2221534e80cc5772ac2b7d222011a2acafc2ec7216d5dd174c864ae/matplotlib-3.10.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:59476c6d29d612b8e9bb6ce8c5b631be6ba8f9e3a2421f22a02b192c7dd28716", size = 9672358, upload-time = "2026-04-24T00:13:28.906Z" }, - { url = "https://files.pythonhosted.org/packages/ab/1a/5a4f747a8b271cbb024946d2dd3c913ab5032ba430626f8c3528ada96b4b/matplotlib-3.10.9-cp314-cp314-win_amd64.whl", hash = "sha256:336b9acc64d309063126edcdaca00db9373af3c476bb94388fe9c5a53ad13e6f", size = 8349970, upload-time = "2026-04-24T00:13:31.904Z" }, - { url = "https://files.pythonhosted.org/packages/64/dc/95d60ecaefe30680a154b52ea96ab4b0dab547f1fd6aa12f5fb655e89cae/matplotlib-3.10.9-cp314-cp314-win_arm64.whl", hash = "sha256:2dc9477819ffd78ad12a20df1d9d6a6bd4fec6aaa9072681465fddca052f1456", size = 8272785, upload-time = "2026-04-24T00:13:34.511Z" }, - { url = "https://files.pythonhosted.org/packages/70/a0/005d68bc8b8418300ce6591f18586910a8526806e2ab663933d9f20a41e9/matplotlib-3.10.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:da4e09638420548f31c354032a6250e473c68e5a4e96899b4844cf39ddea23fe", size = 8367999, upload-time = "2026-04-24T00:13:36.962Z" }, - { url = "https://files.pythonhosted.org/packages/22/05/1236cc9290be70b2498af20ca348add76e3fffe7f67b477db5133a84f3ea/matplotlib-3.10.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:345f6f68ecc8da0ca56fad2ea08fde1a115eda530079eca185d50a7bc3e146c6", size = 8264543, upload-time = "2026-04-24T00:13:39.851Z" }, - { url = "https://files.pythonhosted.org/packages/cd/c2/071f5a5ff6c5bd63aaaf2f45c811d9bf2ced94bde188d9e1a519e21d0cba/matplotlib-3.10.9-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4edcfbd8565339aa62f1cd4012f7180926fdbe71850f7b0d3c379c175cd6b66c", size = 9622800, upload-time = "2026-04-24T00:13:42.296Z" }, - { url = "https://files.pythonhosted.org/packages/95/57/da7d1f10a85624b9e7db68e069dd94e58dc41dbf9463c5921632ecbe3661/matplotlib-3.10.9-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6be157fe17fc37cb95ac1d7374cf717ce9259616edec911a78d9d26dae8522d4", size = 9888561, upload-time = "2026-04-24T00:13:45.026Z" }, - { url = "https://files.pythonhosted.org/packages/67/b2/ef8d6bb59b0edb6c16c968b70f548aa13b54348972def5aa6ac85df67145/matplotlib-3.10.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:4e42042d54db34fda4e95a7bd3e5789c2a995d2dad3eb8850232ee534092fbbf", size = 9680884, upload-time = "2026-04-24T00:13:48.066Z" }, - { url = "https://files.pythonhosted.org/packages/61/1c/d21bfeb9931881ebe96bcfcff27c7ae4b160ae0ec291a714c42641a56d75/matplotlib-3.10.9-cp314-cp314t-win_amd64.whl", hash = "sha256:c27df8b3848f32a83d1767566595e43cfaa4460380974da06f4279a7ec143c39", size = 8432333, upload-time = "2026-04-24T00:13:51.008Z" }, - { url = "https://files.pythonhosted.org/packages/78/23/92493c3e6e1b635ccfff146f7b99e674808787915420373ac399283764c2/matplotlib-3.10.9-cp314-cp314t-win_arm64.whl", hash = "sha256:a49f1eadc84ca85fd72fa4e89e70e61bf86452df6f971af04b12c60761a0772c", size = 8324785, upload-time = "2026-04-24T00:13:53.633Z" }, - { url = "https://files.pythonhosted.org/packages/2c/2b/0e92ad0ac446633f928a1563db4aa8add407e1924faf0ded5b95b35afb27/matplotlib-3.10.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1872fb212a05b729e649754a72d5da61d03e0554d76e80303b6f83d1d2c0552b", size = 8293058, upload-time = "2026-04-24T00:13:56.339Z" }, - { url = "https://files.pythonhosted.org/packages/4b/23/74682fd369f5299ceda438fea2a0662e6383b85c9383fb9cdfcf04713e07/matplotlib-3.10.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:985f2238880e2e69093f588f5fe2e46771747febf0649f3cf7f7b7480875317f", size = 8186627, upload-time = "2026-04-24T00:13:58.623Z" }, - { url = "https://files.pythonhosted.org/packages/ca/e8/368aab88f3c4cd8992800f31abfe0670c3e47540ba20a97e9fdbcde594b3/matplotlib-3.10.9-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6640f75af2c6148293caa0a2b39dd806a492dd66c8a8b04035813e33d0fd2585", size = 8764117, upload-time = "2026-04-24T00:14:01.684Z" }, - { url = "https://files.pythonhosted.org/packages/63/e2/9f66ca6a651a52abfe0d4964ce01439ed34f3f1e119de10ff3a07f403043/matplotlib-3.10.9-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:42fb814efabe95c06c1994d8ab5a8385f43a249e23badd3ba931d4308e5bca20", size = 8304420, upload-time = "2026-04-24T00:14:04.57Z" }, - { url = "https://files.pythonhosted.org/packages/e8/e8/467c03568218792906aa87b5e7bb379b605e056ed0c74fe00c051786d925/matplotlib-3.10.9-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f76e640a5268850bfda54b5131b1b1941cc685e42c5fa98ed9f2d64038308cba", size = 8197981, upload-time = "2026-04-24T00:14:07.233Z" }, - { url = "https://files.pythonhosted.org/packages/6f/87/afead29192170917537934c6aff4b008c805fff7b1ccea0c79120d96beda/matplotlib-3.10.9-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3fc0364dfbe1d07f6d15c5ebd0c5bf89e126916e5a8667dd4a7a6e84c36653d4", size = 8774002, upload-time = "2026-04-24T00:14:09.816Z" }, -] - -[[package]] -name = "numpy" -version = "2.2.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440, upload-time = "2025-05-17T22:38:04.611Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/3e/ed6db5be21ce87955c0cbd3009f2803f59fa08df21b5df06862e2d8e2bdd/numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb", size = 21165245, upload-time = "2025-05-17T21:27:58.555Z" }, - { url = "https://files.pythonhosted.org/packages/22/c2/4b9221495b2a132cc9d2eb862e21d42a009f5a60e45fc44b00118c174bff/numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90", size = 14360048, upload-time = "2025-05-17T21:28:21.406Z" }, - { url = "https://files.pythonhosted.org/packages/fd/77/dc2fcfc66943c6410e2bf598062f5959372735ffda175b39906d54f02349/numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163", size = 5340542, upload-time = "2025-05-17T21:28:30.931Z" }, - { url = "https://files.pythonhosted.org/packages/7a/4f/1cb5fdc353a5f5cc7feb692db9b8ec2c3d6405453f982435efc52561df58/numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf", size = 6878301, upload-time = "2025-05-17T21:28:41.613Z" }, - { url = "https://files.pythonhosted.org/packages/eb/17/96a3acd228cec142fcb8723bd3cc39c2a474f7dcf0a5d16731980bcafa95/numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83", size = 14297320, upload-time = "2025-05-17T21:29:02.78Z" }, - { url = "https://files.pythonhosted.org/packages/b4/63/3de6a34ad7ad6646ac7d2f55ebc6ad439dbbf9c4370017c50cf403fb19b5/numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915", size = 16801050, upload-time = "2025-05-17T21:29:27.675Z" }, - { url = "https://files.pythonhosted.org/packages/07/b6/89d837eddef52b3d0cec5c6ba0456c1bf1b9ef6a6672fc2b7873c3ec4e2e/numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680", size = 15807034, upload-time = "2025-05-17T21:29:51.102Z" }, - { url = "https://files.pythonhosted.org/packages/01/c8/dc6ae86e3c61cfec1f178e5c9f7858584049b6093f843bca541f94120920/numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289", size = 18614185, upload-time = "2025-05-17T21:30:18.703Z" }, - { url = "https://files.pythonhosted.org/packages/5b/c5/0064b1b7e7c89137b471ccec1fd2282fceaae0ab3a9550f2568782d80357/numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d", size = 6527149, upload-time = "2025-05-17T21:30:29.788Z" }, - { url = "https://files.pythonhosted.org/packages/a3/dd/4b822569d6b96c39d1215dbae0582fd99954dcbcf0c1a13c61783feaca3f/numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3", size = 12904620, upload-time = "2025-05-17T21:30:48.994Z" }, - { url = "https://files.pythonhosted.org/packages/da/a8/4f83e2aa666a9fbf56d6118faaaf5f1974d456b1823fda0a176eff722839/numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae", size = 21176963, upload-time = "2025-05-17T21:31:19.36Z" }, - { url = "https://files.pythonhosted.org/packages/b3/2b/64e1affc7972decb74c9e29e5649fac940514910960ba25cd9af4488b66c/numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a", size = 14406743, upload-time = "2025-05-17T21:31:41.087Z" }, - { url = "https://files.pythonhosted.org/packages/4a/9f/0121e375000b5e50ffdd8b25bf78d8e1a5aa4cca3f185d41265198c7b834/numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42", size = 5352616, upload-time = "2025-05-17T21:31:50.072Z" }, - { url = "https://files.pythonhosted.org/packages/31/0d/b48c405c91693635fbe2dcd7bc84a33a602add5f63286e024d3b6741411c/numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491", size = 6889579, upload-time = "2025-05-17T21:32:01.712Z" }, - { url = "https://files.pythonhosted.org/packages/52/b8/7f0554d49b565d0171eab6e99001846882000883998e7b7d9f0d98b1f934/numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a", size = 14312005, upload-time = "2025-05-17T21:32:23.332Z" }, - { url = "https://files.pythonhosted.org/packages/b3/dd/2238b898e51bd6d389b7389ffb20d7f4c10066d80351187ec8e303a5a475/numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf", size = 16821570, upload-time = "2025-05-17T21:32:47.991Z" }, - { url = "https://files.pythonhosted.org/packages/83/6c/44d0325722cf644f191042bf47eedad61c1e6df2432ed65cbe28509d404e/numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1", size = 15818548, upload-time = "2025-05-17T21:33:11.728Z" }, - { url = "https://files.pythonhosted.org/packages/ae/9d/81e8216030ce66be25279098789b665d49ff19eef08bfa8cb96d4957f422/numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab", size = 18620521, upload-time = "2025-05-17T21:33:39.139Z" }, - { url = "https://files.pythonhosted.org/packages/6a/fd/e19617b9530b031db51b0926eed5345ce8ddc669bb3bc0044b23e275ebe8/numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47", size = 6525866, upload-time = "2025-05-17T21:33:50.273Z" }, - { url = "https://files.pythonhosted.org/packages/31/0a/f354fb7176b81747d870f7991dc763e157a934c717b67b58456bc63da3df/numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303", size = 12907455, upload-time = "2025-05-17T21:34:09.135Z" }, - { url = "https://files.pythonhosted.org/packages/82/5d/c00588b6cf18e1da539b45d3598d3557084990dcc4331960c15ee776ee41/numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff", size = 20875348, upload-time = "2025-05-17T21:34:39.648Z" }, - { url = "https://files.pythonhosted.org/packages/66/ee/560deadcdde6c2f90200450d5938f63a34b37e27ebff162810f716f6a230/numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c", size = 14119362, upload-time = "2025-05-17T21:35:01.241Z" }, - { url = "https://files.pythonhosted.org/packages/3c/65/4baa99f1c53b30adf0acd9a5519078871ddde8d2339dc5a7fde80d9d87da/numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3", size = 5084103, upload-time = "2025-05-17T21:35:10.622Z" }, - { url = "https://files.pythonhosted.org/packages/cc/89/e5a34c071a0570cc40c9a54eb472d113eea6d002e9ae12bb3a8407fb912e/numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282", size = 6625382, upload-time = "2025-05-17T21:35:21.414Z" }, - { url = "https://files.pythonhosted.org/packages/f8/35/8c80729f1ff76b3921d5c9487c7ac3de9b2a103b1cd05e905b3090513510/numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87", size = 14018462, upload-time = "2025-05-17T21:35:42.174Z" }, - { url = "https://files.pythonhosted.org/packages/8c/3d/1e1db36cfd41f895d266b103df00ca5b3cbe965184df824dec5c08c6b803/numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", size = 16527618, upload-time = "2025-05-17T21:36:06.711Z" }, - { url = "https://files.pythonhosted.org/packages/61/c6/03ed30992602c85aa3cd95b9070a514f8b3c33e31124694438d88809ae36/numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49", size = 15505511, upload-time = "2025-05-17T21:36:29.965Z" }, - { url = "https://files.pythonhosted.org/packages/b7/25/5761d832a81df431e260719ec45de696414266613c9ee268394dd5ad8236/numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", size = 18313783, upload-time = "2025-05-17T21:36:56.883Z" }, - { url = "https://files.pythonhosted.org/packages/57/0a/72d5a3527c5ebffcd47bde9162c39fae1f90138c961e5296491ce778e682/numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4", size = 6246506, upload-time = "2025-05-17T21:37:07.368Z" }, - { url = "https://files.pythonhosted.org/packages/36/fa/8c9210162ca1b88529ab76b41ba02d433fd54fecaf6feb70ef9f124683f1/numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2", size = 12614190, upload-time = "2025-05-17T21:37:26.213Z" }, - { url = "https://files.pythonhosted.org/packages/f9/5c/6657823f4f594f72b5471f1db1ab12e26e890bb2e41897522d134d2a3e81/numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84", size = 20867828, upload-time = "2025-05-17T21:37:56.699Z" }, - { url = "https://files.pythonhosted.org/packages/dc/9e/14520dc3dadf3c803473bd07e9b2bd1b69bc583cb2497b47000fed2fa92f/numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b", size = 14143006, upload-time = "2025-05-17T21:38:18.291Z" }, - { url = "https://files.pythonhosted.org/packages/4f/06/7e96c57d90bebdce9918412087fc22ca9851cceaf5567a45c1f404480e9e/numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d", size = 5076765, upload-time = "2025-05-17T21:38:27.319Z" }, - { url = "https://files.pythonhosted.org/packages/73/ed/63d920c23b4289fdac96ddbdd6132e9427790977d5457cd132f18e76eae0/numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566", size = 6617736, upload-time = "2025-05-17T21:38:38.141Z" }, - { url = "https://files.pythonhosted.org/packages/85/c5/e19c8f99d83fd377ec8c7e0cf627a8049746da54afc24ef0a0cb73d5dfb5/numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f", size = 14010719, upload-time = "2025-05-17T21:38:58.433Z" }, - { url = "https://files.pythonhosted.org/packages/19/49/4df9123aafa7b539317bf6d342cb6d227e49f7a35b99c287a6109b13dd93/numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f", size = 16526072, upload-time = "2025-05-17T21:39:22.638Z" }, - { url = "https://files.pythonhosted.org/packages/b2/6c/04b5f47f4f32f7c2b0e7260442a8cbcf8168b0e1a41ff1495da42f42a14f/numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868", size = 15503213, upload-time = "2025-05-17T21:39:45.865Z" }, - { url = "https://files.pythonhosted.org/packages/17/0a/5cd92e352c1307640d5b6fec1b2ffb06cd0dabe7d7b8227f97933d378422/numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d", size = 18316632, upload-time = "2025-05-17T21:40:13.331Z" }, - { url = "https://files.pythonhosted.org/packages/f0/3b/5cba2b1d88760ef86596ad0f3d484b1cbff7c115ae2429678465057c5155/numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd", size = 6244532, upload-time = "2025-05-17T21:43:46.099Z" }, - { url = "https://files.pythonhosted.org/packages/cb/3b/d58c12eafcb298d4e6d0d40216866ab15f59e55d148a5658bb3132311fcf/numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c", size = 12610885, upload-time = "2025-05-17T21:44:05.145Z" }, - { url = "https://files.pythonhosted.org/packages/6b/9e/4bf918b818e516322db999ac25d00c75788ddfd2d2ade4fa66f1f38097e1/numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6", size = 20963467, upload-time = "2025-05-17T21:40:44Z" }, - { url = "https://files.pythonhosted.org/packages/61/66/d2de6b291507517ff2e438e13ff7b1e2cdbdb7cb40b3ed475377aece69f9/numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda", size = 14225144, upload-time = "2025-05-17T21:41:05.695Z" }, - { url = "https://files.pythonhosted.org/packages/e4/25/480387655407ead912e28ba3a820bc69af9adf13bcbe40b299d454ec011f/numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40", size = 5200217, upload-time = "2025-05-17T21:41:15.903Z" }, - { url = "https://files.pythonhosted.org/packages/aa/4a/6e313b5108f53dcbf3aca0c0f3e9c92f4c10ce57a0a721851f9785872895/numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8", size = 6712014, upload-time = "2025-05-17T21:41:27.321Z" }, - { url = "https://files.pythonhosted.org/packages/b7/30/172c2d5c4be71fdf476e9de553443cf8e25feddbe185e0bd88b096915bcc/numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f", size = 14077935, upload-time = "2025-05-17T21:41:49.738Z" }, - { url = "https://files.pythonhosted.org/packages/12/fb/9e743f8d4e4d3c710902cf87af3512082ae3d43b945d5d16563f26ec251d/numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa", size = 16600122, upload-time = "2025-05-17T21:42:14.046Z" }, - { url = "https://files.pythonhosted.org/packages/12/75/ee20da0e58d3a66f204f38916757e01e33a9737d0b22373b3eb5a27358f9/numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571", size = 15586143, upload-time = "2025-05-17T21:42:37.464Z" }, - { url = "https://files.pythonhosted.org/packages/76/95/bef5b37f29fc5e739947e9ce5179ad402875633308504a52d188302319c8/numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1", size = 18385260, upload-time = "2025-05-17T21:43:05.189Z" }, - { url = "https://files.pythonhosted.org/packages/09/04/f2f83279d287407cf36a7a8053a5abe7be3622a4363337338f2585e4afda/numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff", size = 6377225, upload-time = "2025-05-17T21:43:16.254Z" }, - { url = "https://files.pythonhosted.org/packages/67/0e/35082d13c09c02c011cf21570543d202ad929d961c02a147493cb0c2bdf5/numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06", size = 12771374, upload-time = "2025-05-17T21:43:35.479Z" }, - { url = "https://files.pythonhosted.org/packages/9e/3b/d94a75f4dbf1ef5d321523ecac21ef23a3cd2ac8b78ae2aac40873590229/numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d", size = 21040391, upload-time = "2025-05-17T21:44:35.948Z" }, - { url = "https://files.pythonhosted.org/packages/17/f4/09b2fa1b58f0fb4f7c7963a1649c64c4d315752240377ed74d9cd878f7b5/numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db", size = 6786754, upload-time = "2025-05-17T21:44:47.446Z" }, - { url = "https://files.pythonhosted.org/packages/af/30/feba75f143bdc868a1cc3f44ccfa6c4b9ec522b36458e738cd00f67b573f/numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543", size = 16643476, upload-time = "2025-05-17T21:45:11.871Z" }, - { url = "https://files.pythonhosted.org/packages/37/48/ac2a9584402fb6c0cd5b5d1a91dcf176b15760130dd386bbafdbfe3640bf/numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00", size = 12812666, upload-time = "2025-05-17T21:45:31.426Z" }, -] - -[[package]] -name = "packaging" -version = "26.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", size = 313412, upload-time = "2026-08-04T18:15:28.737Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" }, -] - -[[package]] -name = "pillow" -version = "12.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1c/3d/bb7fca845737cf9d7dbde16ed1843984665ff2e0a518f5db43e77ec540b9/pillow-12.3.0.tar.gz", hash = "sha256:3b8182a766685eaa002637e28b4ec8d6b18819a0c71f579bf0dbaa5830297cce", size = 47025035, upload-time = "2026-07-01T11:56:38.965Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/25/c2/669d88644cddb1485bd9534e63e8cf476c8e51cb3c3a1297677023505c0e/pillow-12.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6c0016e7b354317c4e9e525b937ac8596c38d2d232b419529b9cd7a1cd46e39a", size = 5392418, upload-time = "2026-07-01T11:53:27.808Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ba/3762f376a2948e3036488d773a146e0ae6ecc2ca03ac20e2615bd0b2ba02/pillow-12.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bcc33feacfaefce60c12fd500a277533bdc02b10a19f7f6d348763d8140bbba7", size = 4785287, upload-time = "2026-07-01T11:53:29.761Z" }, - { url = "https://files.pythonhosted.org/packages/07/50/b5d688cc9c52d4482f3d5bcab6ce20bc2a74a85d2343841c907444a3be2c/pillow-12.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5594fc43d548a7ed94949d139aa1341b270f1863f11cfd37f5a6c8b778a6b67f", size = 6253754, upload-time = "2026-07-01T11:53:32.298Z" }, - { url = "https://files.pythonhosted.org/packages/4e/89/36f4cd76cf4baf05c50ababb976249153f18c959171c7f6ba09a6f217260/pillow-12.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0606c8bf2cdefea14a43530f7657cbbb7ecf1c4222512492ef4a4434a9501ec", size = 6925605, upload-time = "2026-07-01T11:53:34.487Z" }, - { url = "https://files.pythonhosted.org/packages/eb/c0/4de58cf6633b9e3a6061ef4be6fb91fc3c90b812ece886f531e3c523d777/pillow-12.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:85f998ea1848bc6757289e739cfbdda3a04adfd58b02fc018ce54d754a5ce468", size = 6327788, upload-time = "2026-07-01T11:53:36.433Z" }, - { url = "https://files.pythonhosted.org/packages/87/3c/14d53682a19550dbbaf3b598f807d5457646c510805a44c7d7891cd1cd1a/pillow-12.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:25b9b82bb22e6e2b3cd07b39c68b7b862001226cb3dff7130d1cb914121b39ed", size = 7036288, upload-time = "2026-07-01T11:53:38.712Z" }, - { url = "https://files.pythonhosted.org/packages/38/1d/36279e3c77efe034e4cc2b0393ee74ffdb5a62391dacbf9b916154f5f0b8/pillow-12.3.0-cp310-cp310-win32.whl", hash = "sha256:37dc8f7bbb66efe481bb60defacef820c950c24713fb44962ed6aa2a50966de1", size = 6472396, upload-time = "2026-07-01T11:53:40.781Z" }, - { url = "https://files.pythonhosted.org/packages/48/7c/8fa0039574c476d7c6fa57dd7c32a130436877c6ec1e5ce1cc8ec44878c1/pillow-12.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:300557495eb45ebb8aec96c2da9c4be642fbf7cd937278b4013ba894ea8eb0eb", size = 7226887, upload-time = "2026-07-01T11:53:42.764Z" }, - { url = "https://files.pythonhosted.org/packages/fa/17/e324be141d173c1c919428066c3259f21c1b8982e564e01a4a81e96dbdcf/pillow-12.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:514435a37670e3e5e08f3945b68718b6ed329bb84367777e16f9f4dfe1e61a0f", size = 2568039, upload-time = "2026-07-01T11:53:45.372Z" }, - { url = "https://files.pythonhosted.org/packages/fb/c8/0a78b0e02d7ac54bc03e5321c9220da52f0c2ea83b21f7c40e7f3169c502/pillow-12.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:00808c5e14ef63ac5161091d242999076604ff74b883423a11e5d7bbb38bf756", size = 5392415, upload-time = "2026-07-01T11:53:47.162Z" }, - { url = "https://files.pythonhosted.org/packages/b2/5b/a02d30018abd97ced9f5a6c63d28597694a00d066516b9c1c6de45859fc9/pillow-12.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:37d6d0a00072fd2948eb22bce7e1475f34569d90c87c59f7a2ec59541b77f7a6", size = 4785266, upload-time = "2026-07-01T11:53:49.079Z" }, - { url = "https://files.pythonhosted.org/packages/c8/98/766667a4be768150a202836acd9fad19c06824ca86c4286d3cf6b274964e/pillow-12.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bcb46e2f9feff8d06323983bd83ed00c201fdcab3d74973e7072a889b3979fcd", size = 6263814, upload-time = "2026-07-01T11:53:51.32Z" }, - { url = "https://files.pythonhosted.org/packages/3b/2d/ede717bc1144f63886c21fd349bb95860b0d1a21149ff16f2bb362b612b6/pillow-12.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23d27a3e0307ec2244cc51e7287b919aa68d097504ebe19df4e76a98a3eea5bd", size = 6934408, upload-time = "2026-07-01T11:53:53.487Z" }, - { url = "https://files.pythonhosted.org/packages/a3/48/9c58b685e69d49c31af6c8eb9012055fab7e665785165c84796e2c73ce72/pillow-12.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4f883547d4b7f0495ebe7056b0cc2aea76094e7a4abc8e933540f3271df27d9c", size = 6337160, upload-time = "2026-07-01T11:53:55.457Z" }, - { url = "https://files.pythonhosted.org/packages/ff/fa/dc2a5c0ba6df93f67c31d34b808b7ce440b40cdbf96f0b81cde1d1e6fa93/pillow-12.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:236ff70b9312fb68943c703aa842ca6a758abfa45ac187a5e7c1452e96ef72b5", size = 7045172, upload-time = "2026-07-01T11:53:57.736Z" }, - { url = "https://files.pythonhosted.org/packages/86/a5/444817a4d4c4c2417df00513086ca196f388d8f9ef40c2e4ccd1ad1af54b/pillow-12.3.0-cp311-cp311-win32.whl", hash = "sha256:10e41f0fbf1eec8cfd234b8fe17a4caac7c9d0db4c204d3c173a8f9f6ef3232b", size = 6472232, upload-time = "2026-07-01T11:53:59.767Z" }, - { url = "https://files.pythonhosted.org/packages/63/c6/4bad1b18d132a50b27e1365e1ab163616f7a5bb56d330f66f9d1d9d4f9d4/pillow-12.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8e95e1385e4998ae9694eeaa4730ba5457ff61185b3a55e2e7bea0880aef452a", size = 7233653, upload-time = "2026-07-01T11:54:02.066Z" }, - { url = "https://files.pythonhosted.org/packages/fd/16/00f91ab7760dc842f5aad55217e80fc4a7067a0604535249bc8a2d6d9870/pillow-12.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:ebaea975e03d3141d9d3a507df75c9b3ec90fa9d2ffd07567b3a978d9d790b26", size = 2568195, upload-time = "2026-07-01T11:54:04.622Z" }, - { url = "https://files.pythonhosted.org/packages/37/bf/fb3ebff8ddcb76aac5a01389251bbbb9519922a9b520d8247c1ca864a25d/pillow-12.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ba09209fbe443b4acccebe845d8a138b89a8f4fbaeedd44953490b5315d5e965", size = 5345969, upload-time = "2026-07-01T11:54:06.397Z" }, - { url = "https://files.pythonhosted.org/packages/d8/66/9a386a92561f402389a4fc70c18838bf6d35eb5eb5c6850b4b2dc64f5048/pillow-12.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffd0c5368496f41b0944be820fcb7a838aa6e623d250b01acf2643939c3f99d7", size = 4780323, upload-time = "2026-07-01T11:54:09.351Z" }, - { url = "https://files.pythonhosted.org/packages/25/27/ac8f99618ffd3dde21db0f4d4b1d2ab00c0880595bfd17df103f7f39fd0c/pillow-12.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9c7f76c0673154f044e9d78c8655fb4213f6ca31a836df48b40fe5d187717b9", size = 6266838, upload-time = "2026-07-01T11:54:11.71Z" }, - { url = "https://files.pythonhosted.org/packages/84/21/a35af28dcc61f37ed850a2d64c65c701321dfbf25085e469d5559360cbbf/pillow-12.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:78cb2c6865a35ab8ff8b75fd122f6033b92a62c82801110e48ddd6c936a45d91", size = 6940830, upload-time = "2026-07-01T11:54:13.732Z" }, - { url = "https://files.pythonhosted.org/packages/eb/51/8b08617af3ad95e33ce6d7dd2c99ed6c8298f7fb131636303956be022e25/pillow-12.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e491916b378fba47242221bb9ead245211b70d504f495d105d17b14a24b4907c", size = 6344383, upload-time = "2026-07-01T11:54:15.756Z" }, - { url = "https://files.pythonhosted.org/packages/1d/72/cf78ac9780bb93c28328f408973845a309d4d145041665f734572ced1b52/pillow-12.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0dd2064cbc55aaec028ef5fbb60fa47bb6c3e7918e07ff17935284b227a9d2df", size = 7052934, upload-time = "2026-07-01T11:54:17.721Z" }, - { url = "https://files.pythonhosted.org/packages/20/20/25e0f4dc178a6bc0696793720055519a0de89e7661dae886992decbd2f81/pillow-12.3.0-cp312-cp312-win32.whl", hash = "sha256:dbce0b29841537a2fa4a214c2bbf14de3587c9680caa9b4e217568472490b28f", size = 6472684, upload-time = "2026-07-01T11:54:19.839Z" }, - { url = "https://files.pythonhosted.org/packages/45/89/da2f7971a317f83d807fdd4065c0af40208e59e692cc43d315a71a0e96d1/pillow-12.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a2b55dd6b2a4c4b7d87ffa56bdb33fdc5fdb9a462173861a7bc097f17d91cb09", size = 7227137, upload-time = "2026-07-01T11:54:22.025Z" }, - { url = "https://files.pythonhosted.org/packages/de/47/4845a0a6c0dbf1db8456bd9fc791f13c5ced7ced20606d08a0aacfd25b49/pillow-12.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:331b624368d4f1d069149002f25f44bc61c8919ce8ddb3c45bdad8f6e2d89510", size = 2568267, upload-time = "2026-07-01T11:54:24.051Z" }, - { url = "https://files.pythonhosted.org/packages/9d/ac/31fb64e1e7efb5a4b50cd3d92049ba89ac6e4d8d3bb6a74e15048ca3353e/pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:21900ce7ba264168cd50defae43cd75d25c833ad4ad6e73ffc5596d12e25ac89", size = 4161684, upload-time = "2026-07-01T11:54:25.934Z" }, - { url = "https://files.pythonhosted.org/packages/87/b4/9805e23d2b4d77842b468513841fda254ee42f0289d25088340e4ff46e2d/pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:4e8c2a84d977f50b9daed6eeaf3baef67d00d5d74d932288f02cb94518ee3ace", size = 4255487, upload-time = "2026-07-01T11:54:27.935Z" }, - { url = "https://files.pythonhosted.org/packages/df/39/ecf519435a200c693fe053a6ee4d835b41cf963a4dfc2551c4e637cb2a71/pillow-12.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:ae26d61dfa7a47befdc7572b521024e8745f3d809bd95ca9505a7bba9ef849ec", size = 3696433, upload-time = "2026-07-01T11:54:29.813Z" }, - { url = "https://files.pythonhosted.org/packages/42/92/2fc3ffad878ae8dd5469ec1bc8eb83b71f48e13efdf68f02709003982a32/pillow-12.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7a743ff716f746fc19a9557f60dab1600d4613255f8a7aeb3cdde4db7eb15a66", size = 5345889, upload-time = "2026-07-01T11:54:31.97Z" }, - { url = "https://files.pythonhosted.org/packages/10/76/8803c13605b763d33d156c4678fc77f8443389c0c51c8aef707bb02015f4/pillow-12.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d69141514cc30b774ceea5e3ed3a6635c8d8a96edf664689b890f4089111fb35", size = 4780109, upload-time = "2026-07-01T11:54:34.026Z" }, - { url = "https://files.pythonhosted.org/packages/1f/01/e18aff37cb0b4aac47ac90f016d347a49aca667ef97f190b06ac2aabc928/pillow-12.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7401aebd7f581d7f83a439d87d474999317ee099218e5ad25d125290990ba65", size = 6263736, upload-time = "2026-07-01T11:54:36.131Z" }, - { url = "https://files.pythonhosted.org/packages/f7/62/de5bdd77d935331f4f802edc11e4d82950f642caad6cb2f949837b8560e2/pillow-12.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0847a763afefb695bc912d7c131e7e0632d4edc1d8698f58ddabec8e46b8b6d3", size = 6937129, upload-time = "2026-07-01T11:54:38.216Z" }, - { url = "https://files.pythonhosted.org/packages/70/4d/105627a13300c5e0df1d174230b32fd1273062c96f7745fd552b945d1e1d/pillow-12.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:571b9fcb07b97ef3a492028fb3d2dc0993ca23a06138b0315286566d29ef718a", size = 6339562, upload-time = "2026-07-01T11:54:40.354Z" }, - { url = "https://files.pythonhosted.org/packages/6b/1d/f13de01a553988ab895ba1c722e06cf3144d4f57656fd5b81b6d881f1179/pillow-12.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:756c768d0c9c2955feb7a56c37ea24aea2e369f8d36a88da270b6a9f19e62b5e", size = 7049439, upload-time = "2026-07-01T11:54:42.489Z" }, - { url = "https://files.pythonhosted.org/packages/c9/f9/066794cca041b969964f779ee5fa66a9498bbf34248ac39c5d7954e4198f/pillow-12.3.0-cp313-cp313-win32.whl", hash = "sha256:a876864214e136f0eb367788dbd7df045f4806801518e2cfe9e13229cfe06d8f", size = 6473287, upload-time = "2026-07-01T11:54:44.9Z" }, - { url = "https://files.pythonhosted.org/packages/a6/9b/7a58e61d62be561da3a356fe2384d4059a6345fc130e23ef1c36a5b81d24/pillow-12.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:1cca606cd25738df4ed873d5ad46bbdb3d83b5cbca291f6b4ff13a4df6b0bbe8", size = 7239691, upload-time = "2026-07-01T11:54:47.141Z" }, - { url = "https://files.pythonhosted.org/packages/aa/b0/c4ed4f0ef8f8fa5ee8351537db6650bb8189f7e118842978dd6589065692/pillow-12.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:b629de27fda84b42cde7edef0d85f13b958b47f6e9bbcbba9b673c562a89bd8b", size = 2568185, upload-time = "2026-07-01T11:54:49.137Z" }, - { url = "https://files.pythonhosted.org/packages/dc/01/001f65b68192f0228cc1dbbc8d2530ab5d58b61037ba0587f946fea607cd/pillow-12.3.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:9cf95fe4d0f84c82d282745d9bb08ad9f926efa00be4697e767b814ce40d4330", size = 4161736, upload-time = "2026-07-01T11:54:51.156Z" }, - { url = "https://files.pythonhosted.org/packages/1a/d2/0219746d0fd16fc8a84498e79452375be3797d3ce4044596ce565164b84f/pillow-12.3.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:8728f216dcdb6e6d555cf971cb34076139ad74b31fc2c14da4fafc741c5f6217", size = 4255435, upload-time = "2026-07-01T11:54:53.414Z" }, - { url = "https://files.pythonhosted.org/packages/c8/02/8d0bc62ef0302318c46ff2a512822d2610e81c7aa46c9b3abe6cbaca5ad0/pillow-12.3.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:a45650e8ce7fafffd731db8550230db6b0d306d181a90b67d3e6bca2f1990930", size = 3696262, upload-time = "2026-07-01T11:54:55.739Z" }, - { url = "https://files.pythonhosted.org/packages/85/e2/73c77d218410b14f5f2d565e8a998d5317b7b9c75368d29985139f7a46f0/pillow-12.3.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ba54cfebe86920a559a7c4d6b9050791c20513650a1952ebe3368c7dc70306f8", size = 5350344, upload-time = "2026-07-01T11:54:57.657Z" }, - { url = "https://files.pythonhosted.org/packages/c7/da/32c752228ae345f489e3a42499d817b6c3996da7e8a3bc7a04fc806b243b/pillow-12.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e158cb00350dc278f3b91551101aa7d12415a66ebf2c91d8d5ac14e56ddd3ad0", size = 4780131, upload-time = "2026-07-01T11:54:59.713Z" }, - { url = "https://files.pythonhosted.org/packages/b1/9d/8b2c807dbef61a5197c047afe99823787eb66f63daf9fb2432f91d6f0462/pillow-12.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9aeb04d6aef139de265b29683e119b638208f88cf73cdd1658aa07221165321", size = 6263757, upload-time = "2026-07-01T11:55:01.778Z" }, - { url = "https://files.pythonhosted.org/packages/5c/44/c85361f65dbe00eea8576ee467c768d25129989efb76e94f205e9ca9bb46/pillow-12.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:251bf95b67017e27b13d82f5b326234ca62d70f9cf4c2b9032de2358a3b12c7b", size = 6936962, upload-time = "2026-07-01T11:55:03.93Z" }, - { url = "https://files.pythonhosted.org/packages/18/7e/e483414b35800b86b6f08dbbc7803fb5cd52c4d6f897f47d53ea2c7e6f65/pillow-12.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fe3cca2e4e8a592be0f269a1ca4835c25199d9f3ce815c8491048f785b0a0198", size = 6339171, upload-time = "2026-07-01T11:55:05.989Z" }, - { url = "https://files.pythonhosted.org/packages/f0/f4/68c491844841ede6bed70189546b3ee9731cf9f2cbad396faff5e1ccba45/pillow-12.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:23aceaa007d6172b02c277f0cd359c79492bbb14f7072b4ede9fbcaf20648130", size = 7048116, upload-time = "2026-07-01T11:55:08.131Z" }, - { url = "https://files.pythonhosted.org/packages/a3/34/77f3f793fed8efc7d243f21b33c5a3f0d1c97ee70346d3db855587e155ff/pillow-12.3.0-cp314-cp314-win32.whl", hash = "sha256:af8d94b0db561cf68b88a267c5c44b49e134f525d0dc2cb7ed413a66bc23559a", size = 6467209, upload-time = "2026-07-01T11:55:10.408Z" }, - { url = "https://files.pythonhosted.org/packages/f1/e0/492879f69d94f91f60fc8cd05ba03650e9520afebb2fb7aa12777d7c7f38/pillow-12.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:fdafc9cce40277e0f7a0feabce0ee50dd2fa1800f3b38015e51296b5e814048d", size = 7237707, upload-time = "2026-07-01T11:55:12.745Z" }, - { url = "https://files.pythonhosted.org/packages/c9/ac/6b11f2875f1c2ac040d84e1bbf9cf22a88038f901ca1037898b280b38365/pillow-12.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:e91206ee562682b51b98ef4b26a6ef48fd84e15fd4c4bc5ec768eb641d206838", size = 2565995, upload-time = "2026-07-01T11:55:14.736Z" }, - { url = "https://files.pythonhosted.org/packages/52/69/c2208e56af9bfc1913afb24020297a691eb1d4ef688474c8a04913f65e04/pillow-12.3.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:164b31cd1a0490ab6efae01aa5df49da7061be0af1b30e035b6e9a1bfe34ee6e", size = 5352503, upload-time = "2026-07-01T11:55:17.076Z" }, - { url = "https://files.pythonhosted.org/packages/07/70/e5686d753e898a45d778ff1718dba8516ead6ab6b95d85fc8c4b70650cf2/pillow-12.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5afb51d599ea772b8365ae807ae557f18bccfe46ab261fd1c2a9ed700fc6eb17", size = 4782956, upload-time = "2026-07-01T11:55:19.448Z" }, - { url = "https://files.pythonhosted.org/packages/d5/37/25c6692f06927ee973ff18c8d9ee98ad0b4d84ee67a09610c2dd1447958e/pillow-12.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3edce1d53195db527e0191f84b71d02022de0540bf43a16ed734ed7537b07385", size = 6322855, upload-time = "2026-07-01T11:55:21.613Z" }, - { url = "https://files.pythonhosted.org/packages/cc/91/420637fcb8f1bc11029e403b4538e6694744428d8246118e45719f944556/pillow-12.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf16ba1b4d0b6b7c8e534936632270cf70eb00dbe09005bc345b2677b726855c", size = 6989642, upload-time = "2026-07-01T11:55:24.006Z" }, - { url = "https://files.pythonhosted.org/packages/10/08/b94d7811281ccf0d143a1cf768d1c49e1e54af63e7b708ab2ee3eb87face/pillow-12.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:24870b09b224f7ae3c39ed07d10e819d06f8720bc551847b1d623832b5b0e28d", size = 6391281, upload-time = "2026-07-01T11:55:26.252Z" }, - { url = "https://files.pythonhosted.org/packages/d2/87/24233f785f55474dc02ce3e739c5528a77e3a862e9333d1dd7a25cc31f70/pillow-12.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:30f2aa603c41533cc25c05acd0da21636e84a315768feb631c937177db558931", size = 7096716, upload-time = "2026-07-01T11:55:28.318Z" }, - { url = "https://files.pythonhosted.org/packages/23/26/fcb2f6e37175b04f53570b59937867e2b80ee1685e744023153028fc14f9/pillow-12.3.0-cp314-cp314t-win32.whl", hash = "sha256:4b0a7fe987b14c31ebda6083f74f22b561fd3739bc0ac51e019622e3d72668c7", size = 6474125, upload-time = "2026-07-01T11:55:30.956Z" }, - { url = "https://files.pythonhosted.org/packages/90/de/3634abee5f1c9e13c56787b7d5517b0ba8d6de51700b95578cf338349c9f/pillow-12.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:962864dc93511324d51ddbb5b9f8731bf71675b93ca612a07441896f4688fb8c", size = 7242939, upload-time = "2026-07-01T11:55:34.044Z" }, - { url = "https://files.pythonhosted.org/packages/ce/2a/fd13f8eb24de5714a6eb444a3d67e2842c6c576e159a43793adf23051351/pillow-12.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0740a512dc522224c77d9aa5a8d70d8b7d73fb91f2c21125d8d025d3b8990e45", size = 2567506, upload-time = "2026-07-01T11:55:35.988Z" }, - { url = "https://files.pythonhosted.org/packages/5d/dc/8fdce34ec725a33c81c6ba122b904d6b9024e50ea9ac7bede62fab54506c/pillow-12.3.0-cp315-cp315-ios_13_0_arm64_iphoneos.whl", hash = "sha256:0feb2e9d6ad6c9e3c06effe9d00f3f1e618a6643273576b016f591e9315a7139", size = 4162063, upload-time = "2026-07-01T11:55:37.941Z" }, - { url = "https://files.pythonhosted.org/packages/76/66/2044b9a63d3b84ff048228dfcb7cd9bf0df983e8470971bf7d4c57b693de/pillow-12.3.0-cp315-cp315-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:9e881fca225083806662a5c43d627d215f258ff43c890f831966c7d7ba9c7402", size = 4255549, upload-time = "2026-07-01T11:55:40.022Z" }, - { url = "https://files.pythonhosted.org/packages/52/7e/1f67e6f4ece6b582ee4b539decbcc9f848dc245a93ed8cd7338bafef72f1/pillow-12.3.0-cp315-cp315-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:4998562bf62a445225f22e07c896bb04b35b1b1f2eb6d760584c9c51d7a5f78c", size = 3696331, upload-time = "2026-07-01T11:55:41.98Z" }, - { url = "https://files.pythonhosted.org/packages/12/40/d306fc2c8e4d45d7f175c77edca7063be7b86fe7fe6e68f4353bf71d808c/pillow-12.3.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:dc624f6bc473dacdf7ef7eb8678d0d08edf15cd94fad6ae5c7d6cc67a4e4902f", size = 5350370, upload-time = "2026-07-01T11:55:44.028Z" }, - { url = "https://files.pythonhosted.org/packages/dd/44/668fb1437e8ce420f62d6106eb66e44a5971602a4d794615bdf79315d82d/pillow-12.3.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:71d6097b330eea8fd15097780c8e89cb1a8ce7838669f48c5bacd6f663dd4701", size = 4780147, upload-time = "2026-07-01T11:55:46.073Z" }, - { url = "https://files.pythonhosted.org/packages/0c/08/93fa2e70e30a2d81547e481b6ee2bb9522117221fb1e0ce4b5df70967677/pillow-12.3.0-cp315-cp315-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:28ce87c5ab450a9dd970b52e5aca5fe63ed432d18a2eaddd1979a00a1ba24ace", size = 6273659, upload-time = "2026-07-01T11:55:48.264Z" }, - { url = "https://files.pythonhosted.org/packages/f8/6d/043e96ff814fc31a33077e4cba86082167db520c93632afdf2042febbb0c/pillow-12.3.0-cp315-cp315-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b02afb9b97f65fbca5f31db6a2a3ba21aa93030225f150fa3f249717e938fb4", size = 6947439, upload-time = "2026-07-01T11:55:50.503Z" }, - { url = "https://files.pythonhosted.org/packages/af/92/ba71d2ee2ac0edf3fa33bd9d5ee9ee080da70b1766f3ca3934f9938ddac9/pillow-12.3.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:1182d52bc2d5e5d7d0949503aa7e36d12f42205dc287e4883f407b1988820d39", size = 6353577, upload-time = "2026-07-01T11:55:52.697Z" }, - { url = "https://files.pythonhosted.org/packages/0f/ce/e63064e2122923ff687c8ad792d0d736a7b3920a56a46982e81a7fdd25d6/pillow-12.3.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:e795b7eb908249c4e43c7c99fac7c2c75dab0c43566e37db472a355f63693d71", size = 7060394, upload-time = "2026-07-01T11:55:55.149Z" }, - { url = "https://files.pythonhosted.org/packages/54/76/a09cc3ccc8d773a7283d34c38bec1708f9e3cc932093cbc4c5e71ac4060b/pillow-12.3.0-cp315-cp315-win32.whl", hash = "sha256:57b3d78c95ba9059768b10e28b813002261d3f3dfc55cc48b0c988f625175827", size = 6467375, upload-time = "2026-07-01T11:55:57.769Z" }, - { url = "https://files.pythonhosted.org/packages/3e/03/1846c49ba3b1d5550392a4bbd06d6fb4578e1cd91a803198b5c90f5f7d53/pillow-12.3.0-cp315-cp315-win_amd64.whl", hash = "sha256:fa4ecea169a355be7a3ade2c783e2ed12f0e40d2c5621cda8b3297faf7fbb9f5", size = 7237048, upload-time = "2026-07-01T11:55:59.975Z" }, - { url = "https://files.pythonhosted.org/packages/fb/bb/89f35dcc79610423f9f195504d7def7f0d1416a711541b42867e25fe3412/pillow-12.3.0-cp315-cp315-win_arm64.whl", hash = "sha256:877c3f311ff35410f690861c4409e7ccbf0cd2f878e50628a28e5a0bb689e658", size = 2566006, upload-time = "2026-07-01T11:56:02.143Z" }, - { url = "https://files.pythonhosted.org/packages/30/88/707027ba09942dfa2c28759b5c222d769290a41c6d20ea60ec250801941f/pillow-12.3.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:e9871b1ffbfa9656b60aeee92ed5136a5742696006fa322b29ea3d8da0ecc9cf", size = 5352509, upload-time = "2026-07-01T11:56:04.2Z" }, - { url = "https://files.pythonhosted.org/packages/b0/6d/00352fa25332c2569cd387851f568cc5a4b75a9adbfb37ac4fbce4c02eec/pillow-12.3.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:53aa02d20d10c3d814d536aa4e5ac9b84ca0ff5a88377963b085ad6822f93e64", size = 4783167, upload-time = "2026-07-01T11:56:06.631Z" }, - { url = "https://files.pythonhosted.org/packages/13/4f/9e049dfa21af7c22427275720e2490267ba8138120add5c4c574deb69782/pillow-12.3.0-cp315-cp315t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:446c34dcc4324b084a53b705127dc15717b22c5e140ae0a3c38349d4efec071e", size = 6329237, upload-time = "2026-07-01T11:56:08.868Z" }, - { url = "https://files.pythonhosted.org/packages/36/16/cf6eeaae8d0fce8dd390a33437cf68c5d5bd73834a2bc6e2f14efda0ab45/pillow-12.3.0-cp315-cp315t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf1845d02ad822a369a49f2bb9345b1614744267682e7a03527dc3bf6eea1777", size = 6997047, upload-time = "2026-07-01T11:56:11.379Z" }, - { url = "https://files.pythonhosted.org/packages/1e/69/dbf769bdd55f48bf5733cac28edc6364ffaa072ec9ba336266e4fe66be55/pillow-12.3.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:186941b6aef820ad110fb01fb06eb925374dc3a21b17e37ec9a53b250c6fe2d1", size = 6400440, upload-time = "2026-07-01T11:56:13.908Z" }, - { url = "https://files.pythonhosted.org/packages/a0/e1/ffc9cfc2eea0d178da8018e18e959301ad9d6bc9f3edb7181e748a474b97/pillow-12.3.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:f13c32a3abd6079a66d9526e18dad9b6d280384d49d7c54040cd57b6424041d9", size = 7105895, upload-time = "2026-07-01T11:56:16.575Z" }, - { url = "https://files.pythonhosted.org/packages/18/f0/a5595c1e8c3ae44b9828cb2f0fa8155e5095ef04d6327b8f61cf44a3df85/pillow-12.3.0-cp315-cp315t-win32.whl", hash = "sha256:1657923d2d45afb66526e5b933e5b3052e6bdea196c90d3abb2424e18c77dae8", size = 6474384, upload-time = "2026-07-01T11:56:18.855Z" }, - { url = "https://files.pythonhosted.org/packages/e4/04/62bcd9f844984c5938d3b05264a61d797a29d3e0812341a8204af70bbdee/pillow-12.3.0-cp315-cp315t-win_amd64.whl", hash = "sha256:8cd2f7bdda092d99c9fc2fb7391354f306d01443d22785d0cbfafa2e2c8bb418", size = 7243537, upload-time = "2026-07-01T11:56:21.214Z" }, - { url = "https://files.pythonhosted.org/packages/3d/68/1f3066acedf37673694a7141381d8f811ae97f30d34413d236abe7d489f1/pillow-12.3.0-cp315-cp315t-win_arm64.whl", hash = "sha256:06ff022112bc9cbf83b60f8e028d94ad87b60621706487e65f673de61610ab59", size = 2567491, upload-time = "2026-07-01T11:56:23.506Z" }, - { url = "https://files.pythonhosted.org/packages/75/18/2e8b40223153ccbc60df07f9e8928dc0c76202aa4e55ae9f53962b6510d6/pillow-12.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b3c777e849237620b022f7f297dd67705f9f5cf1685f09f02e46f93e92725468", size = 5302510, upload-time = "2026-07-01T11:56:25.736Z" }, - { url = "https://files.pythonhosted.org/packages/46/3e/51fabf59d5ab801ceab709453d3ab6b180083496579549de4c45ced6528a/pillow-12.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b343699e8308bdc51978310e1c959c584e7869cc8c40780058c87da7781a1e94", size = 4736058, upload-time = "2026-07-01T11:56:28.041Z" }, - { url = "https://files.pythonhosted.org/packages/bf/20/22fe9384b7949e25fb1293bcfc84fb82590ff4ea6b37c95b24d26d793d86/pillow-12.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbd139c8447d25dd750ab79ee274cc5e1fe80fc56340ab10b18a195e1b6eca3e", size = 5237776, upload-time = "2026-07-01T11:56:30.263Z" }, - { url = "https://files.pythonhosted.org/packages/08/14/f6ba68107680ffa74b39985f3f30884e41318fbc4250caa423c79b4788bb/pillow-12.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e7e480451b9fa137494bccd3a7d69adbe8ac65a87d97be61e11f1b1050a5bac3", size = 5860358, upload-time = "2026-07-01T11:56:32.68Z" }, - { url = "https://files.pythonhosted.org/packages/36/54/0169bc772ec491108b62f644f8ecf1fe5d8ae5ebafde2ee2142210166903/pillow-12.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:04f01d28a6aaff387bf842a13be313df23ba0597a44f1a976c9feb3c6ff4711a", size = 7231786, upload-time = "2026-07-01T11:56:35.046Z" }, -] - -[[package]] -name = "pluggy" -version = "1.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, -] - -[[package]] -name = "pydantic" -version = "2.13.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775, upload-time = "2026-05-06T13:43:05.343Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba", size = 472262, upload-time = "2026-05-06T13:43:02.641Z" }, -] - -[[package]] -name = "pydantic-core" -version = "2.46.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/08/f1ba952f1c8ae5581c70fa9c6da89f247b83e3dd8c09c035d5d7931fc23d/pydantic_core-2.46.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a396dcc17e5a0b164dbe026896245a4fa9ff402edca1dff0be3d53a517f74de4", size = 2113146, upload-time = "2026-05-06T13:37:36.537Z" }, - { url = "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:da4b951fe36dc7c3a1ccb4e3cd1747c3542b8c9ceede8fc86cae054e764485f5", size = 1949769, upload-time = "2026-05-06T13:37:46.365Z" }, - { url = "https://files.pythonhosted.org/packages/64/ba/bfb1d928fd5b49e1258935ff104ae356e9fd89384a55bf9f847e9193ad40/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb63e0198ca18aad131c089b9204c23079c3afa95487e561f4c522d519e55aba", size = 1974958, upload-time = "2026-05-06T13:37:28.611Z" }, - { url = "https://files.pythonhosted.org/packages/4e/74/76223bfb117b64af743c9b6670d1364516f5c0604f96b48f3272f6af6cc6/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f47286a97f0bc9b8859519809077b91b2cefe4ae47fcbf5e466a009c1c5d742b", size = 2042118, upload-time = "2026-05-06T13:36:55.216Z" }, - { url = "https://files.pythonhosted.org/packages/cb/7b/848732968bc8f48f3187542f08358b9d842db564147b256669426ebb1652/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:905a0ed8ea6f2d61c1738835f99b699348d7857379083e5fc497fa0c967a407c", size = 2222876, upload-time = "2026-05-06T13:38:25.455Z" }, - { url = "https://files.pythonhosted.org/packages/b5/2f/e90b63ee2e14bd8d3db8f705a6d75d64e6ee1b7c2c8833747ce706e1e0ce/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea793e075b70290d89d8142074262885d3f7da19634845135751bd6344f73b50", size = 2286703, upload-time = "2026-05-06T13:37:53.304Z" }, - { url = "https://files.pythonhosted.org/packages/ba/1e/acc4d70f88a0a277e4a1fa77ebb985ceabaf900430f875bf9338e11c9420/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:395aebd9183f9d112f569aeb5b2214d1a10a33bec8456447f7fbdfa51d38d4cd", size = 2092042, upload-time = "2026-05-06T13:38:46.981Z" }, - { url = "https://files.pythonhosted.org/packages/a9/da/0a422b57bf8504102bf3c4ccea9c41bab5a5cee6a54650acf8faf67f5a24/pydantic_core-2.46.4-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:b078afbc25f3a1436c7a1d2cd3e322497ee99615ba97c563566fdf46aff1ee01", size = 2117231, upload-time = "2026-05-06T13:39:23.146Z" }, - { url = "https://files.pythonhosted.org/packages/bd/2a/2ac13c3af305843e23c5078c53d135656b3f05a2fd78cb7bbbb12e97b473/pydantic_core-2.46.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f747929cf940cddb5b3668a390056ddd5ba2e5010615ea2dcf4f9c4f3ab8791d", size = 2168388, upload-time = "2026-05-06T13:40:08.06Z" }, - { url = "https://files.pythonhosted.org/packages/72/04/2beacf7e1607e93eefe4aed1b4709f079b905fb77530179d4f7c71745f22/pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:daa27d92c36f24388fe3ad306b174781c747627f134452e4f128ea00ce1fe8c4", size = 2184769, upload-time = "2026-05-06T13:38:13.901Z" }, - { url = "https://files.pythonhosted.org/packages/9e/29/d2b9fd9f539133548eaf622c06a4ce176cb46ac59f32d0359c4abc0de047/pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:19e51f073cd3df251856a8a4189fbdf1de4012c3ebacfb1884f94f1eb406079f", size = 2319312, upload-time = "2026-05-06T13:39:08.24Z" }, - { url = "https://files.pythonhosted.org/packages/7c/af/0f7a5b85fec6075bea96e3ef9187de38fccced0de92c1e7feda8d5cc7bb9/pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1747f85cee84c26985853c6f3d9bd3e75da5212912443fa111c113b9c246f39", size = 2361817, upload-time = "2026-05-06T13:38:43.2Z" }, - { url = "https://files.pythonhosted.org/packages/25/a4/73363fec545fd3ec025490bdda2743c56d0dd5b6266b1a53bbe9e4265375/pydantic_core-2.46.4-cp310-cp310-win32.whl", hash = "sha256:2f84c03c8607173d16b5a854ec68a2f9079ae03237a54fb506d13af47e1d018d", size = 1987085, upload-time = "2026-05-06T13:39:25.497Z" }, - { url = "https://files.pythonhosted.org/packages/01/aa/62f082da2c91fac1c234bc9ee0066257ce83f0604abd72e4c9d5991f2d84/pydantic_core-2.46.4-cp310-cp310-win_amd64.whl", hash = "sha256:8358a950c8909158e3df31538a7e4edc2d7265a7c54b47f0864d9e5bae9dcebf", size = 2074311, upload-time = "2026-05-06T13:39:59.922Z" }, - { url = "https://files.pythonhosted.org/packages/5c/fa/6d7708d2cfc1a832acb6aeb0cd16e801902df8a0f583bb3b4b527fde022e/pydantic_core-2.46.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0e96592440881c74a213e5ad528e2b24d3d4f940de2766bed9010ab1d9e51594", size = 2111872, upload-time = "2026-05-06T13:40:27.596Z" }, - { url = "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0d65b8c354be7fb5f720c3caa8bc940bc2d20ce749c8e06135f07f8ed95dd7c", size = 1948255, upload-time = "2026-05-06T13:39:12.574Z" }, - { url = "https://files.pythonhosted.org/packages/43/3a/41114a9f7569b84b4d84e7a018c57c56347dac30c0d4a872946ec4e36c46/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bfb192b3f4b9e8a89b6277b6ce787564f62cfd272055f6e685726b111dc7826", size = 1972827, upload-time = "2026-05-06T13:38:19.841Z" }, - { url = "https://files.pythonhosted.org/packages/ef/25/1ab42e8048fe551934d9884e8d64daa7e990ad386f310a15981aeb6a5b08/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9037063db01f09b09e237c282b6792bd4da634b5402c4e7f0c61effed7701a04", size = 2041051, upload-time = "2026-05-06T13:38:10.447Z" }, - { url = "https://files.pythonhosted.org/packages/94/c2/1a934597ddf08da410385b3b7aae91956a5a76c635effef456074fad7e88/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc010ab034c8c7452522748bf937df58020d256ccae0874463d1f4d01758af8e", size = 2221314, upload-time = "2026-05-06T13:40:13.089Z" }, - { url = "https://files.pythonhosted.org/packages/02/6d/9e8ad178c9c4df27ad3c8f25d1fe2a7ab0d2ba0559fad4aee5d3d1f16771/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5dac79fa1614d1e06ca695109c6105923bd9c7d1d6c918d4e637b7e6b32fd3", size = 2285146, upload-time = "2026-05-06T13:38:59.224Z" }, - { url = "https://files.pythonhosted.org/packages/80/50/540cd3aeefc041beb111125c4bff779831a2111fc6b15a9138cda277d32c/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9fa868638bf362d3d138ea55829cefb3d5f4b0d7f142234382a15e2485dbec4", size = 2089685, upload-time = "2026-05-06T13:38:17.762Z" }, - { url = "https://files.pythonhosted.org/packages/6b/a4/b440ad35f05f6a38f89fa0f149accb3f0e02be94ca5e15f3c449a61b4bc9/pydantic_core-2.46.4-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:17299feefe090f2caa5b8e37222bb5f663e4935a8bfa6931d4102e5df1a9f398", size = 2115420, upload-time = "2026-05-06T13:37:58.195Z" }, - { url = "https://files.pythonhosted.org/packages/99/61/de4f55db8dfd57bfdfa9a12ec90fe1b57c4f41062f7ca86f08586b3e0ac0/pydantic_core-2.46.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c63ebc82684aa89d9a3bcbd13d515b3be44250dc68dd3bd81526c1cb31286c3", size = 2165122, upload-time = "2026-05-06T13:37:01.167Z" }, - { url = "https://files.pythonhosted.org/packages/f7/52/7c529d7bdb2d1068bd52f51fe32572c8301f9a4febf1948f10639f1436f5/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aaa2a54443eff1950ba5ddc6b6ccda0d9c84a364276a62f969bdf2a390650848", size = 2182573, upload-time = "2026-05-06T13:38:45.04Z" }, - { url = "https://files.pythonhosted.org/packages/37/b3/7c40325848ba78247f2812dcf9c7274e38cd801820ca6dd9fe63bcfb0eb4/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:18e5ceec2ab67e6d5f1a9085e5a24c9c4e2ac4545730bfe668680bca05e555f3", size = 2317139, upload-time = "2026-05-06T13:37:15.539Z" }, - { url = "https://files.pythonhosted.org/packages/d9/37/f913f81a657c865b75da6c0dbed79876073c2a43b5bd9edbe8da785e4d49/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a0f62d0a58f4e7da165457e995725421e0064f2255d8eccebc49f41bbc23b109", size = 2360433, upload-time = "2026-05-06T13:37:30.099Z" }, - { url = "https://files.pythonhosted.org/packages/c4/67/6acaa1be2567f9256b056d8477158cac7240813956ce86e49deae8e173b4/pydantic_core-2.46.4-cp311-cp311-win32.whl", hash = "sha256:041bde0a48fd37cf71cab1c9d56d3e8625a3793fef1f7dd232b3ff37e978ecda", size = 1985513, upload-time = "2026-05-06T13:38:15.669Z" }, - { url = "https://files.pythonhosted.org/packages/aa/e6/c505f83dfeda9a2e5c995cfd872949e4d05e12f7feb3dca72f633daefa94/pydantic_core-2.46.4-cp311-cp311-win_amd64.whl", hash = "sha256:6f2eeda33a839975441c86a4119e1383c50b47faf0cbb5176985565c6bb02c33", size = 2071114, upload-time = "2026-05-06T13:40:35.416Z" }, - { url = "https://files.pythonhosted.org/packages/0f/da/7a263a96d965d9d0df5e8de8a475f33495451117035b09acb110288c381f/pydantic_core-2.46.4-cp311-cp311-win_arm64.whl", hash = "sha256:14f4c5d6db102bd796a627bbb3a17b4cf4574b9ae861d8b7c9a9661c6dd3362d", size = 2044298, upload-time = "2026-05-06T13:38:29.754Z" }, - { url = "https://files.pythonhosted.org/packages/ce/8c/af022f0af448d7747c5154288d46b5f2bc5f17366eaa0e23e9aa04d59f3b/pydantic_core-2.46.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3245406455a5d98187ec35530fd772b1d799b26667980872c8d4614991e2c4a2", size = 2106158, upload-time = "2026-05-06T13:38:57.215Z" }, - { url = "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:962ccbab7b642487b1d8b7df90ef677e03134cf1fd8880bf698649b22a69371f", size = 1951724, upload-time = "2026-05-06T13:37:02.697Z" }, - { url = "https://files.pythonhosted.org/packages/8e/bc/f47d1ff9cbb1620e1b5b697eef06010035735f07820180e74178226b27b3/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8233f2947cf85404441fd7e0085f53b10c93e0ee78611099b5c7237e36aacbf7", size = 1975742, upload-time = "2026-05-06T13:37:09.448Z" }, - { url = "https://files.pythonhosted.org/packages/5b/11/9b9a5b0306345664a2da6410877af6e8082481b5884b3ddd78d47c6013ce/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a233125ac121aa3ffba9a2b59edfc4a985a76092dc8279586ab4b71390875e7", size = 2052418, upload-time = "2026-05-06T13:37:38.234Z" }, - { url = "https://files.pythonhosted.org/packages/f1/b7/a65fec226f5d78fc39f4a13c4cc0c768c22b113438f60c14adc9d2865038/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b712b53160b79a5850310b912a5ef8e57e56947c8ad690c227f5c9d7e561712", size = 2232274, upload-time = "2026-05-06T13:38:27.753Z" }, - { url = "https://files.pythonhosted.org/packages/68/f0/92039db98b907ef49269a8271f67db9cb78ae2fc68062ef7e4e77adb5f61/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9401557acd873c3a7f3eb9383edef8ac4968f9510e340f4808d427e75667e7b4", size = 2309940, upload-time = "2026-05-06T13:38:05.353Z" }, - { url = "https://files.pythonhosted.org/packages/5f/97/2aab507d3d00ca626e8e57c1eac6a79e4e5fbcc63eb99733ff55d1717f65/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:926c9541b14b12b1681dca8a0b75feb510b06c6341b70a8e500c2fdcff837cce", size = 2094516, upload-time = "2026-05-06T13:39:10.577Z" }, - { url = "https://files.pythonhosted.org/packages/22/37/a8aca44d40d737dde2bc05b3c6c07dff0de07ce6f82e9f3167aeaf4d5dea/pydantic_core-2.46.4-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:56cb4851bcaf3d117eddcef4fe66afd750a50274b0da8e22be256d10e5611987", size = 2136854, upload-time = "2026-05-06T13:40:22.59Z" }, - { url = "https://files.pythonhosted.org/packages/24/99/fcef1b79238c06a8cbec70819ac722ba76e02bc8ada9b0fd66eba40da01b/pydantic_core-2.46.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c68fcd102d71ea85c5b2dfac3f4f8476eff42a9e078fd5faefff6d145063536b", size = 2180306, upload-time = "2026-05-06T13:40:10.666Z" }, - { url = "https://files.pythonhosted.org/packages/ae/6c/fc44000918855b42779d007ae63b0532794739027b2f417321cddbc44f6a/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b2f69dec1725e79a012d920df1707de5caf7ed5e08f3be4435e25803efc47458", size = 2190044, upload-time = "2026-05-06T13:40:43.231Z" }, - { url = "https://files.pythonhosted.org/packages/6b/65/d9cadc9f1920d7a127ad2edba16c1db7916e59719285cd6c94600b0080ba/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:8d0820e8192167f80d88d64038e609c31452eeca865b4e1d9950a27a4609b00b", size = 2329133, upload-time = "2026-05-06T13:39:57.365Z" }, - { url = "https://files.pythonhosted.org/packages/d0/cf/c873d91679f3a30bcf5e7ac280ce5573483e72295307685120d0d5ad3416/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fbdb89b3e1c94a30cc5edfce477c6e6a5dc4d8f84665b455c27582f211a1c72c", size = 2374464, upload-time = "2026-05-06T13:38:06.976Z" }, - { url = "https://files.pythonhosted.org/packages/47/bd/6f2fc8188f31bf10590f1e98e7b306336161fac930a8c514cd7bd828c7dc/pydantic_core-2.46.4-cp312-cp312-win32.whl", hash = "sha256:9aa768456404a8bf48a4406685ac2bec8e72b62c69313734fa3b73cf33b3a894", size = 1974823, upload-time = "2026-05-06T13:40:47.985Z" }, - { url = "https://files.pythonhosted.org/packages/40/8c/985c1d41ea1107c2534abd9870e4ed5c8e7669b5c308297835c001e7a1c4/pydantic_core-2.46.4-cp312-cp312-win_amd64.whl", hash = "sha256:e9c26f834c65f5752f3f06cb08cb86a913ceb7274d0db6e267808a708b46bc89", size = 2072919, upload-time = "2026-05-06T13:39:21.153Z" }, - { url = "https://files.pythonhosted.org/packages/c4/ba/f463d006e0c47373ca7ec5e1a261c59dc01ef4d62b2657af925fb0deee3a/pydantic_core-2.46.4-cp312-cp312-win_arm64.whl", hash = "sha256:4fc73cb559bdb54b1134a706a2802a4cddd27a0633f5abb7e53056268751ac6a", size = 2027604, upload-time = "2026-05-06T13:39:03.753Z" }, - { url = "https://files.pythonhosted.org/packages/51/a2/5d30b469c5267a17b39dec53208222f76a8d351dfac4af661888c5aee77d/pydantic_core-2.46.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5d5902252db0d3cedf8d4a1bc68f70eeb430f7e4c7104c8c476753519b423008", size = 2106306, upload-time = "2026-05-06T13:37:48.029Z" }, - { url = "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94f0688e7b8d0a67abf40e57a7eaaecd17cc9586706a31b76c031f63df052b4", size = 1951906, upload-time = "2026-05-06T13:37:17.012Z" }, - { url = "https://files.pythonhosted.org/packages/03/d5/fd02da45b659668b05923b17ba3a0100a0a3d5541e3bd8fcc4ecb711309e/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f027324c56cd5406ca49c124b0db10e56c69064fec039acc571c29020cc87c76", size = 1976802, upload-time = "2026-05-06T13:37:35.113Z" }, - { url = "https://files.pythonhosted.org/packages/21/f2/95727e1368be3d3ed485eaab7adbd7dda408f33f7a36e8b48e0144002b91/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e739fee756ba1010f8bcccb534252e85a35fe45ae92c295a06059ce58b74ccd3", size = 2052446, upload-time = "2026-05-06T13:37:12.313Z" }, - { url = "https://files.pythonhosted.org/packages/9c/86/5d99feea3f77c7234b8718075b23db11532773c1a0dbd9b9490215dc2eeb/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d56801be94b86a9da183e5f3766e6310752b99ff647e38b09a9500d88e46e76", size = 2232757, upload-time = "2026-05-06T13:39:01.149Z" }, - { url = "https://files.pythonhosted.org/packages/d2/3a/508ac615935ef7588cf6d9e9b91309fdc2da751af865e02a9098de88258c/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2412e734dcb48da14d4e4006b82b46b74f2518b8a26ee7e58c6844a6cd6d03c4", size = 2309275, upload-time = "2026-05-06T13:37:41.406Z" }, - { url = "https://files.pythonhosted.org/packages/07/f8/41db9de19d7987d6b04715a02b3b40aea467000275d9d758ffaa31af7d50/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9551187363ffc0de2a00b2e47c25aeaeb1020b69b668762966df15fc5659dd5a", size = 2094467, upload-time = "2026-05-06T13:39:18.847Z" }, - { url = "https://files.pythonhosted.org/packages/2c/e2/f35033184cb11d0052daf4416e8e10a502ea2ac006fc4f459aee872727d1/pydantic_core-2.46.4-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0186750b482eefa11d7f435892b09c5c606193ef3375bcf94aa00ae6bfb66262", size = 2134417, upload-time = "2026-05-06T13:40:17.944Z" }, - { url = "https://files.pythonhosted.org/packages/7e/7b/6ceeb1cc90e193862f444ebe373d8fdf613f0a82572dde03fb10734c6c71/pydantic_core-2.46.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5855698a4856556d86e8e6cd8434bc3ac0314ee8e12089ae0e143f64c6256e4e", size = 2179782, upload-time = "2026-05-06T13:40:32.618Z" }, - { url = "https://files.pythonhosted.org/packages/5a/f2/c8d7773ede6af08036423a00ae0ceffce266c3c52a096c435d68c896083f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cbaf13819775b7f769bf4a1f066cb6df7a28d4480081a589828ef190226881cd", size = 2188782, upload-time = "2026-05-06T13:36:51.018Z" }, - { url = "https://files.pythonhosted.org/packages/59/31/0c864784e31f09f05cdd87606f08923b9c9e7f6e51dd27f20f62f975ce9f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:633147d34cf4550417f12e2b1a0383973bdf5cdfde212cb09e9a581cf10820be", size = 2328334, upload-time = "2026-05-06T13:40:37.764Z" }, - { url = "https://files.pythonhosted.org/packages/c2/eb/4f6c8a41efa30baa755590f4141abf3a8c370fab610915733e74134a7270/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:82cf5301172168103724d49a1444d3378cb20cdee30b116a1bd6031236298a5d", size = 2372986, upload-time = "2026-05-06T13:39:34.152Z" }, - { url = "https://files.pythonhosted.org/packages/5b/24/b375a480d53113860c299764bfe9f349a3dc9108b3adc0d7f0d786492ebf/pydantic_core-2.46.4-cp313-cp313-win32.whl", hash = "sha256:9fa8ae11da9e2b3126c6426f147e0fba88d96d65921799bb30c6abd1cb2c97fb", size = 1973693, upload-time = "2026-05-06T13:37:55.072Z" }, - { url = "https://files.pythonhosted.org/packages/7e/e8/cff247591966f2d22ec8c003cd7587e27b7ba7b81ab2fb888e3ab75dc285/pydantic_core-2.46.4-cp313-cp313-win_amd64.whl", hash = "sha256:6b3ace8194b0e5204818c92802dcdca7fc6d88aabbb799d7c795540d9cd6d292", size = 2071819, upload-time = "2026-05-06T13:38:49.139Z" }, - { url = "https://files.pythonhosted.org/packages/c6/1a/f4aee670d5670e9e148e0c82c7db98d780be566c6e6a97ee8035528ca0b3/pydantic_core-2.46.4-cp313-cp313-win_arm64.whl", hash = "sha256:184c081504d17f1c1066e430e117142b2c77d9448a97f7b65c6ac9fd9aee238d", size = 2027411, upload-time = "2026-05-06T13:40:45.796Z" }, - { url = "https://files.pythonhosted.org/packages/8d/74/228a26ddad29c6672b805d9fd78e8d251cd04004fa7eed0e622096cd0250/pydantic_core-2.46.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:428e04521a40150c85216fc8b85e8d39fece235a9cf5e383761238c7fa9b96fb", size = 2102079, upload-time = "2026-05-06T13:38:41.019Z" }, - { url = "https://files.pythonhosted.org/packages/ad/1f/8970b150a4b4365623ae00fc88603491f763c627311ae8031e3111356d6e/pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23ace664830ee0bfe014a0c7bc248b1f7f25ed7ad103852c317624a1083af462", size = 1952179, upload-time = "2026-05-06T13:36:59.812Z" }, - { url = "https://files.pythonhosted.org/packages/95/30/5211a831ae054928054b2f79731661087a2bc5c01e825c672b3a4a8f1b3e/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce5c1d2a8b27468f433ca974829c44060b8097eedc39933e3c206a90ee49c4a9", size = 1978926, upload-time = "2026-05-06T13:37:39.933Z" }, - { url = "https://files.pythonhosted.org/packages/57/e9/689668733b1eb67adeef047db3c2e8788fcf65a7fd9c9e2b46b7744fe245/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7283d57845ecf5a163403eb0702dfc220cc4fbdd18919cb5ccea4f95ee1cdab4", size = 2046785, upload-time = "2026-05-06T13:38:01.995Z" }, - { url = "https://files.pythonhosted.org/packages/60/d9/6715260422ff50a2109878fd24d948a6c3446bb2664f34ee78cd972b3acd/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8daafc69c93ee8a0204506a3b6b30f586ef54028f52aeeeb5c4cfc5184fd5914", size = 2228733, upload-time = "2026-05-06T13:40:50.371Z" }, - { url = "https://files.pythonhosted.org/packages/18/ae/fdb2f64316afca925640f8e70bb1a564b0ec2721c1389e25b8eb4bf9a299/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2213145bcc2ba85884d0ac63d222fece9209678f77b9b4d76f054c561adb28", size = 2307534, upload-time = "2026-05-06T13:37:21.531Z" }, - { url = "https://files.pythonhosted.org/packages/89/1d/8eff589b45bb8190a9d12c49cfad0f176a5cbd1534908a6b5125e2886239/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a5f930472650a82629163023e630d160863fce524c616f4e5186e5de9d9a49b", size = 2099732, upload-time = "2026-05-06T13:39:31.942Z" }, - { url = "https://files.pythonhosted.org/packages/06/d5/ee5a3366637fee41dee51a1fc91562dcf12ddbc68fda34e6b253da2324bb/pydantic_core-2.46.4-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:c1b3f518abeca3aa13c712fd202306e145abf59a18b094a6bafb2d2bbf59192c", size = 2129627, upload-time = "2026-05-06T13:37:25.033Z" }, - { url = "https://files.pythonhosted.org/packages/94/33/2414be571d2c6a6c4d08be21f9292b6d3fdb08949a97b6dfe985017821db/pydantic_core-2.46.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a7dd0b3ee80d90150e3495a3a13ac34dbcbfd4f012996a6a1d8900e91b5c0fb", size = 2179141, upload-time = "2026-05-06T13:37:14.046Z" }, - { url = "https://files.pythonhosted.org/packages/7b/79/7daa95be995be0eecc4cf75064cb33f9bbbfe3fe0158caf2f0d4a996a5c7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:3fb702cd90b0446a3a1c5e470bfa0dd23c0233b676a9099ddcc964fa6ca13898", size = 2184325, upload-time = "2026-05-06T13:36:53.615Z" }, - { url = "https://files.pythonhosted.org/packages/9f/cb/d0a382f5c0de8a222dc61c65348e0ce831b1f68e0a018450d31c2cace3a5/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b8458003118a712e66286df6a707db01c52c0f52f7db8e4a38f0da1d3b94fc4e", size = 2323990, upload-time = "2026-05-06T13:40:29.971Z" }, - { url = "https://files.pythonhosted.org/packages/05/db/d9ba624cc4a5aced1598e88c04fdbd8310c8a69b9d38b9a3d39ce3a61ed7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:372429a130e469c9cd698925ce5fc50940b7a1336b0d82038e63d5bbc4edc519", size = 2369978, upload-time = "2026-05-06T13:37:23.027Z" }, - { url = "https://files.pythonhosted.org/packages/f2/20/d15df15ba918c423461905802bfd2981c3af0bfa0e40d05e13edbfa48bc3/pydantic_core-2.46.4-cp314-cp314-win32.whl", hash = "sha256:85bb3611ff1802f3ee7fdd7dbff26b56f343fb432d57a4728fdd49b6ef35e2f4", size = 1966354, upload-time = "2026-05-06T13:38:03.499Z" }, - { url = "https://files.pythonhosted.org/packages/fc/b6/6b8de4c0a7d7ab3004c439c80c5c1e0a3e8d78bbae19379b01960383d9e5/pydantic_core-2.46.4-cp314-cp314-win_amd64.whl", hash = "sha256:811ff8e9c313ab425368bcbb36e5c4ebd7108c2bbf4e4089cfbb0b01eff63fac", size = 2072238, upload-time = "2026-05-06T13:39:40.807Z" }, - { url = "https://files.pythonhosted.org/packages/32/36/51eb763beec1f4cf59b1db243a7dcc39cbb41230f050a09b9d69faaf0a48/pydantic_core-2.46.4-cp314-cp314-win_arm64.whl", hash = "sha256:bfec22eab3c8cc2ceec0248aec886624116dc079afa027ecc8ad4a7e62010f8a", size = 2018251, upload-time = "2026-05-06T13:37:26.72Z" }, - { url = "https://files.pythonhosted.org/packages/e8/91/855af51d625b23aa987116a19e231d2aaef9c4a415273ddc189b79a45fee/pydantic_core-2.46.4-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:af8244b2bef6aaad6d92cda81372de7f8c8d36c9f0c3ea36e827c60e7d9467a0", size = 2099593, upload-time = "2026-05-06T13:39:47.682Z" }, - { url = "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a4330cdbc57162e4b3aa303f588ba752257694c9c9be3e7ebb11b4aca659b5d", size = 1935226, upload-time = "2026-05-06T13:40:40.428Z" }, - { url = "https://files.pythonhosted.org/packages/e8/e7/1955d28d1afc56dd4b3ad7cc0cf39df1b9852964cf16e5d13912756d6d6b/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c61fc04a3d840155ff08e475a04809278972fe6aef51e2720554e96367e34b", size = 1974605, upload-time = "2026-05-06T13:37:32.029Z" }, - { url = "https://files.pythonhosted.org/packages/93/e2/3fedbf0ba7a22850e6e9fd78117f1c0f10f950182344d8a6c535d468fdd8/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c50f2528cf200c5eed56faf3f4e22fcd5f38c157a8b78576e6ba3168ec35f000", size = 2030777, upload-time = "2026-05-06T13:38:55.239Z" }, - { url = "https://files.pythonhosted.org/packages/f8/61/46be275fcaaba0b4f5b9669dd852267ce1ff616592dccf7a7845588df091/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0cbe8b01f948de4286c74cdd6c667aceb38f5c1e26f0693b3983d9d74887c65e", size = 2236641, upload-time = "2026-05-06T13:37:08.096Z" }, - { url = "https://files.pythonhosted.org/packages/60/db/12e93e46a8bac9988be3c016860f83293daea8c716c029c9ace279036f2f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:617d7e2ca7dcb8c5cf6bcb8c59b8832c94b36196bbf1cbd1bfb56ed341905edd", size = 2286404, upload-time = "2026-05-06T13:40:20.221Z" }, - { url = "https://files.pythonhosted.org/packages/e2/4a/4d8b19008f38d31c53b8219cfedc2e3d5de5fe99d90076b7e767de29274f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7027560ee92211647d0d34e3f7cd6f50da56399d26a9c8ad0da286d3869a53f3", size = 2109219, upload-time = "2026-05-06T13:38:12.153Z" }, - { url = "https://files.pythonhosted.org/packages/88/70/3cbc40978fefb7bb09c6708d40d4ad1a5d70fd7213c3d17f971de868ec1f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:f99626688942fb746e545232e7726926f3be91b5975f8b55327665fafda991c7", size = 2110594, upload-time = "2026-05-06T13:40:02.971Z" }, - { url = "https://files.pythonhosted.org/packages/9d/20/b8d36736216e29491125531685b2f9e61aa5b4b2599893f8268551da3338/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc3e9034a63de20e15e8ade85358bc6efc614008cab72898b4b4952bea0509ff", size = 2159542, upload-time = "2026-05-06T13:39:27.506Z" }, - { url = "https://files.pythonhosted.org/packages/1d/a2/367df868eb584dacf6bf82a389272406d7178e301c4ac82545ab98bc2dd9/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:97e7cf2be5c77b7d1a9713a05605d49460d02c6078d38d8bef3cbe323c548424", size = 2168146, upload-time = "2026-05-06T13:38:31.93Z" }, - { url = "https://files.pythonhosted.org/packages/c1/b8/4460f77f7e201893f649a29ab355dddd3beee8a97bcb1a320db414f9a06e/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:3bf92c5d0e00fefaab325a4d27828fe6b6e2a21848686b5b60d2d9eeb09d76c6", size = 2306309, upload-time = "2026-05-06T13:37:44.717Z" }, - { url = "https://files.pythonhosted.org/packages/64/c4/be2639293acd87dc8ddbcec41a73cee9b2ebf996fe6d892a1a74e88ad3f7/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:3ecbc122d18468d06ca279dc26a8c2e2d5acb10943bb35e36ae92096dc3b5565", size = 2369736, upload-time = "2026-05-06T13:37:05.645Z" }, - { url = "https://files.pythonhosted.org/packages/30/a6/9f9f380dbb301f67023bf8f707aaa75daadf84f7152d95c410fd7e81d994/pydantic_core-2.46.4-cp314-cp314t-win32.whl", hash = "sha256:e846ae7835bf0703ae43f534ab79a867146dadd59dc9ca5c8b53d5c8f7c9ef02", size = 1955575, upload-time = "2026-05-06T13:38:51.116Z" }, - { url = "https://files.pythonhosted.org/packages/40/1f/f1eb9eb350e795d1af8586289746f5c5677d16043040d63710e22abc43c9/pydantic_core-2.46.4-cp314-cp314t-win_amd64.whl", hash = "sha256:2108ba5c1c1eca18030634489dc544844144ee36357f2f9f780b93e7ddbb44b5", size = 2051624, upload-time = "2026-05-06T13:38:21.672Z" }, - { url = "https://files.pythonhosted.org/packages/f6/d2/42dd53d0a85c27606f316d3aa5d2869c4e8470a5ed6dec30e4a1abe19192/pydantic_core-2.46.4-cp314-cp314t-win_arm64.whl", hash = "sha256:4fcbe087dbc2068af7eda3aa87634eba216dbda64d1ae73c8684b621d33f6596", size = 2017325, upload-time = "2026-05-06T13:40:52.723Z" }, - { url = "https://files.pythonhosted.org/packages/ee/a4/73995fd4ebbb46ba0ee51e6fa049b8f02c40daebb762208feda8a6b7894d/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:14d4edf427bdcf950a8a02d7cb44a08614388dd6e1bdcbf4f67504fa7887da9c", size = 2111589, upload-time = "2026-05-06T13:37:10.817Z" }, - { url = "https://files.pythonhosted.org/packages/fb/7f/f37d3a5e8bfcc2e403f5c57a730f2d815693fb42119e8ea48b3789335af1/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:0ce40cd7b21210e99342afafbd4d0f76d784eb5b1d60f3bdc566be4983c6c73b", size = 1944552, upload-time = "2026-05-06T13:36:56.717Z" }, - { url = "https://files.pythonhosted.org/packages/15/3c/d7eb777b3ff43e8433a4efb39a17aa8fd98a4ee8561a24a67ef5db07b2d6/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90884113d8b48f760e9587002789ddd741e76ab9f89518cd1e43b1f1a52ec44b", size = 1982984, upload-time = "2026-05-06T13:39:06.207Z" }, - { url = "https://files.pythonhosted.org/packages/63/87/70b9f40170a81afd55ca26c9b2acb25c20d64bcfbf888fafecb3ba077d4c/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66ce7632c22d837c95301830e111ad0128a32b8207533b60896a96c4915192ea", size = 2138417, upload-time = "2026-05-06T13:39:45.476Z" }, - { url = "https://files.pythonhosted.org/packages/9d/1d/8987ad40f65ae1432753072f214fb5c74fe47ffbd0698bb9cbbb585664f8/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:1d8ba486450b14f3b1d63bc521d410ec7565e52f887b9fb671791886436a42f7", size = 2095527, upload-time = "2026-05-06T13:39:52.283Z" }, - { url = "https://files.pythonhosted.org/packages/64/d3/84c282a7eee1d3ac4c0377546ef5a1ea436ce26840d9ac3b7ed54a377507/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:3009f12e4e90b7f88b4f9adb1b0c4a3d58fe7820f3238c190047209d148026df", size = 1936024, upload-time = "2026-05-06T13:40:15.671Z" }, - { url = "https://files.pythonhosted.org/packages/d7/ca/eac61596cdeb4d7e174d3dc0bd8a6238f14f75f97a24e7b7db4c7e7340a0/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad785e92e6dc634c21555edc8bd6b64957ab844541bcb96a1366c202951ae526", size = 1990696, upload-time = "2026-05-06T13:38:34.717Z" }, - { url = "https://files.pythonhosted.org/packages/fa/c3/7c8b240552251faf6b3a957db200fcfbbcec36763c050428b601e0c9b83b/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00c603d540afdd6b80eb39f078f33ebd46211f02f33e34a32d9f053bba711de0", size = 2147590, upload-time = "2026-05-06T13:39:29.883Z" }, - { url = "https://files.pythonhosted.org/packages/11/cb/428de0385b6c8d44b716feba566abfacfbd23ee3c4439faa789a1456242f/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0c563b08bca408dc7f65f700633d8442fffb2421fc47b8101377e9fd65051ff0", size = 2112782, upload-time = "2026-05-06T13:37:04.016Z" }, - { url = "https://files.pythonhosted.org/packages/0b/b5/6a17bdadd0fc1f170adfd05a20d37c832f52b117b4d9131da1f41bb097ce/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:db06ffe51636ffe9ca531fe9023dd64bdd794be8754cb5df57c5498ae5b518a7", size = 1952146, upload-time = "2026-05-06T13:39:43.092Z" }, - { url = "https://files.pythonhosted.org/packages/2a/dc/03734d80e362cd43ef65428e9de77c730ce7f2f11c60d2b1e1b39f0fbf99/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:133878133d271ade3d41d1bfb2a45ec38dbdbda40bc065921c6b04e4630127e2", size = 2134492, upload-time = "2026-05-06T13:36:58.124Z" }, - { url = "https://files.pythonhosted.org/packages/de/df/5e5ffc085ed07cc22d298134d3d911c63e91f6a0eb91fe646750a3209910/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9bc519fbf2b7578398853d815009ae5e4d4603d12f4e3f91da8c06852d3da3e9", size = 2156604, upload-time = "2026-05-06T13:37:49.88Z" }, - { url = "https://files.pythonhosted.org/packages/81/44/6e112a4253e56f5705467cbab7ab5e91ee7398ba3d56d358635958893d3e/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c7a7bd4e39e8e4c12c39cd480356842b6a8a06e41b23a55a5e3e191718838ddf", size = 2183828, upload-time = "2026-05-06T13:37:43.053Z" }, - { url = "https://files.pythonhosted.org/packages/ac/ad/5565071e937d8e752842ac241463944c9eb14c87e2d269f2658a5bd05e98/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:d396ec2b979760aaf3218e76c24e65bd0aca24983298653b3a9d7a45f9e47b30", size = 2310000, upload-time = "2026-05-06T13:37:56.694Z" }, - { url = "https://files.pythonhosted.org/packages/4f/c3/66883a5cec183e7fba4d024b4cbbe61851a63750ef606b0afecc46d1f2bf/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:86e1a4418c6cd97d60c95c71164158eaf7324fae7b0923264016baa993eba6fc", size = 2361286, upload-time = "2026-05-06T13:40:05.667Z" }, - { url = "https://files.pythonhosted.org/packages/4b/2d/69abac8f838090bbecd5df894befb2c2619e7996a98ddb949db9f3b93225/pydantic_core-2.46.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:d51026d73fcfd93610abc7b27789c26b313920fcfb20e27462d74a7f8b06e983", size = 2193071, upload-time = "2026-05-06T13:38:08.682Z" }, -] - -[[package]] -name = "pygments" -version = "2.21.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/2e/ced460408999b33da6b31b0021b0f37d329e202d4169aeb164493778f25b/pygments-2.21.0.tar.gz", hash = "sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c", size = 5005329, upload-time = "2026-08-17T08:02:48.824Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl", hash = "sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9", size = 1250147, upload-time = "2026-08-17T08:02:44.912Z" }, -] - -[[package]] -name = "pyparsing" -version = "3.3.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, -] - -[[package]] -name = "pytest" -version = "9.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "iniconfig" }, - { name = "packaging" }, - { name = "pluggy" }, - { name = "pygments" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, -] - -[[package]] -name = "pytest-dotenv" -version = "0.5.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pytest" }, - { name = "python-dotenv" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/cd/b0/cafee9c627c1bae228eb07c9977f679b3a7cb111b488307ab9594ba9e4da/pytest-dotenv-0.5.2.tar.gz", hash = "sha256:2dc6c3ac6d8764c71c6d2804e902d0ff810fa19692e95fe138aefc9b1aa73732", size = 3782, upload-time = "2020-06-16T12:38:03.4Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/da/9da67c67b3d0963160e3d2cbc7c38b6fae342670cc8e6d5936644b2cf944/pytest_dotenv-0.5.2-py3-none-any.whl", hash = "sha256:40a2cece120a213898afaa5407673f6bd924b1fa7eafce6bda0e8abffe2f710f", size = 3993, upload-time = "2020-06-16T12:38:01.139Z" }, -] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, -] - -[[package]] -name = "python-dotenv" -version = "1.2.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6a/53/ed9d74092561d4b01a2ef1349d52cdbc135e526c245f366b089cfca6de49/python_dotenv-1.2.3.tar.gz", hash = "sha256:a20a594dabeaa385725aa239d5244871c143ecb356add8a20fcf23773a6c3a35", size = 58945, upload-time = "2026-08-16T16:54:54.067Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl", hash = "sha256:904552145e8bfed22162c09dab1c2b9b54fefa7b23ba780f4f26ca0316b0f0d9", size = 22780, upload-time = "2026-08-16T16:54:52.473Z" }, -] - -[[package]] -name = "ruff" -version = "0.11.13" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ed/da/9c6f995903b4d9474b39da91d2d626659af3ff1eeb43e9ae7c119349dba6/ruff-0.11.13.tar.gz", hash = "sha256:26fa247dc68d1d4e72c179e08889a25ac0c7ba4d78aecfc835d49cbfd60bf514", size = 4282054, upload-time = "2025-06-05T21:00:15.721Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/ce/a11d381192966e0b4290842cc8d4fac7dc9214ddf627c11c1afff87da29b/ruff-0.11.13-py3-none-linux_armv6l.whl", hash = "sha256:4bdfbf1240533f40042ec00c9e09a3aade6f8c10b6414cf11b519488d2635d46", size = 10292516, upload-time = "2025-06-05T20:59:32.944Z" }, - { url = "https://files.pythonhosted.org/packages/78/db/87c3b59b0d4e753e40b6a3b4a2642dfd1dcaefbff121ddc64d6c8b47ba00/ruff-0.11.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:aef9c9ed1b5ca28bb15c7eac83b8670cf3b20b478195bd49c8d756ba0a36cf48", size = 11106083, upload-time = "2025-06-05T20:59:37.03Z" }, - { url = "https://files.pythonhosted.org/packages/77/79/d8cec175856ff810a19825d09ce700265f905c643c69f45d2b737e4a470a/ruff-0.11.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53b15a9dfdce029c842e9a5aebc3855e9ab7771395979ff85b7c1dedb53ddc2b", size = 10436024, upload-time = "2025-06-05T20:59:39.741Z" }, - { url = "https://files.pythonhosted.org/packages/8b/5b/f6d94f2980fa1ee854b41568368a2e1252681b9238ab2895e133d303538f/ruff-0.11.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab153241400789138d13f362c43f7edecc0edfffce2afa6a68434000ecd8f69a", size = 10646324, upload-time = "2025-06-05T20:59:42.185Z" }, - { url = "https://files.pythonhosted.org/packages/6c/9c/b4c2acf24ea4426016d511dfdc787f4ce1ceb835f3c5fbdbcb32b1c63bda/ruff-0.11.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c51f93029d54a910d3d24f7dd0bb909e31b6cd989a5e4ac513f4eb41629f0dc", size = 10174416, upload-time = "2025-06-05T20:59:44.319Z" }, - { url = "https://files.pythonhosted.org/packages/f3/10/e2e62f77c65ede8cd032c2ca39c41f48feabedb6e282bfd6073d81bb671d/ruff-0.11.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1808b3ed53e1a777c2ef733aca9051dc9bf7c99b26ece15cb59a0320fbdbd629", size = 11724197, upload-time = "2025-06-05T20:59:46.935Z" }, - { url = "https://files.pythonhosted.org/packages/bb/f0/466fe8469b85c561e081d798c45f8a1d21e0b4a5ef795a1d7f1a9a9ec182/ruff-0.11.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d28ce58b5ecf0f43c1b71edffabe6ed7f245d5336b17805803312ec9bc665933", size = 12511615, upload-time = "2025-06-05T20:59:49.534Z" }, - { url = "https://files.pythonhosted.org/packages/17/0e/cefe778b46dbd0cbcb03a839946c8f80a06f7968eb298aa4d1a4293f3448/ruff-0.11.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55e4bc3a77842da33c16d55b32c6cac1ec5fb0fbec9c8c513bdce76c4f922165", size = 12117080, upload-time = "2025-06-05T20:59:51.654Z" }, - { url = "https://files.pythonhosted.org/packages/5d/2c/caaeda564cbe103bed145ea557cb86795b18651b0f6b3ff6a10e84e5a33f/ruff-0.11.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:633bf2c6f35678c56ec73189ba6fa19ff1c5e4807a78bf60ef487b9dd272cc71", size = 11326315, upload-time = "2025-06-05T20:59:54.469Z" }, - { url = "https://files.pythonhosted.org/packages/75/f0/782e7d681d660eda8c536962920c41309e6dd4ebcea9a2714ed5127d44bd/ruff-0.11.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ffbc82d70424b275b089166310448051afdc6e914fdab90e08df66c43bb5ca9", size = 11555640, upload-time = "2025-06-05T20:59:56.986Z" }, - { url = "https://files.pythonhosted.org/packages/5d/d4/3d580c616316c7f07fb3c99dbecfe01fbaea7b6fd9a82b801e72e5de742a/ruff-0.11.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4a9ddd3ec62a9a89578c85842b836e4ac832d4a2e0bfaad3b02243f930ceafcc", size = 10507364, upload-time = "2025-06-05T20:59:59.154Z" }, - { url = "https://files.pythonhosted.org/packages/5a/dc/195e6f17d7b3ea6b12dc4f3e9de575db7983db187c378d44606e5d503319/ruff-0.11.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d237a496e0778d719efb05058c64d28b757c77824e04ffe8796c7436e26712b7", size = 10141462, upload-time = "2025-06-05T21:00:01.481Z" }, - { url = "https://files.pythonhosted.org/packages/f4/8e/39a094af6967faa57ecdeacb91bedfb232474ff8c3d20f16a5514e6b3534/ruff-0.11.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:26816a218ca6ef02142343fd24c70f7cd8c5aa6c203bca284407adf675984432", size = 11121028, upload-time = "2025-06-05T21:00:04.06Z" }, - { url = "https://files.pythonhosted.org/packages/5a/c0/b0b508193b0e8a1654ec683ebab18d309861f8bd64e3a2f9648b80d392cb/ruff-0.11.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:51c3f95abd9331dc5b87c47ac7f376db5616041173826dfd556cfe3d4977f492", size = 11602992, upload-time = "2025-06-05T21:00:06.249Z" }, - { url = "https://files.pythonhosted.org/packages/7c/91/263e33ab93ab09ca06ce4f8f8547a858cc198072f873ebc9be7466790bae/ruff-0.11.13-py3-none-win32.whl", hash = "sha256:96c27935418e4e8e77a26bb05962817f28b8ef3843a6c6cc49d8783b5507f250", size = 10474944, upload-time = "2025-06-05T21:00:08.459Z" }, - { url = "https://files.pythonhosted.org/packages/46/f4/7c27734ac2073aae8efb0119cae6931b6fb48017adf048fdf85c19337afc/ruff-0.11.13-py3-none-win_amd64.whl", hash = "sha256:29c3189895a8a6a657b7af4e97d330c8a3afd2c9c8f46c81e2fc5a31866517e3", size = 11548669, upload-time = "2025-06-05T21:00:11.147Z" }, - { url = "https://files.pythonhosted.org/packages/ec/bf/b273dd11673fed8a6bd46032c0ea2a04b2ac9bfa9c628756a5856ba113b0/ruff-0.11.13-py3-none-win_arm64.whl", hash = "sha256:b4385285e9179d608ff1d2fb9922062663c658605819a6876d8beef0c30b7f3b", size = 10683928, upload-time = "2025-06-05T21:00:13.758Z" }, -] - -[[package]] -name = "six" -version = "1.17.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, -] - -[[package]] -name = "tomli" -version = "2.4.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/11/db3d5885d8528263d8adc260bb2d28ebf1270b96e98f0e0268d32b8d9900/tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30", size = 154704, upload-time = "2026-03-25T20:21:10.473Z" }, - { url = "https://files.pythonhosted.org/packages/6d/f7/675db52c7e46064a9aa928885a9b20f4124ecb9bc2e1ce74c9106648d202/tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a", size = 149454, upload-time = "2026-03-25T20:21:12.036Z" }, - { url = "https://files.pythonhosted.org/packages/61/71/81c50943cf953efa35bce7646caab3cf457a7d8c030b27cfb40d7235f9ee/tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076", size = 237561, upload-time = "2026-03-25T20:21:13.098Z" }, - { url = "https://files.pythonhosted.org/packages/48/c1/f41d9cb618acccca7df82aaf682f9b49013c9397212cb9f53219e3abac37/tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9", size = 243824, upload-time = "2026-03-25T20:21:14.569Z" }, - { url = "https://files.pythonhosted.org/packages/22/e4/5a816ecdd1f8ca51fb756ef684b90f2780afc52fc67f987e3c61d800a46d/tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c", size = 242227, upload-time = "2026-03-25T20:21:15.712Z" }, - { url = "https://files.pythonhosted.org/packages/6b/49/2b2a0ef529aa6eec245d25f0c703e020a73955ad7edf73e7f54ddc608aa5/tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc", size = 247859, upload-time = "2026-03-25T20:21:17.001Z" }, - { url = "https://files.pythonhosted.org/packages/83/bd/6c1a630eaca337e1e78c5903104f831bda934c426f9231429396ce3c3467/tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049", size = 97204, upload-time = "2026-03-25T20:21:18.079Z" }, - { url = "https://files.pythonhosted.org/packages/42/59/71461df1a885647e10b6bb7802d0b8e66480c61f3f43079e0dcd315b3954/tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e", size = 108084, upload-time = "2026-03-25T20:21:18.978Z" }, - { url = "https://files.pythonhosted.org/packages/b8/83/dceca96142499c069475b790e7913b1044c1a4337e700751f48ed723f883/tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece", size = 95285, upload-time = "2026-03-25T20:21:20.309Z" }, - { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload-time = "2026-03-25T20:21:21.626Z" }, - { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload-time = "2026-03-25T20:21:23.002Z" }, - { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload-time = "2026-03-25T20:21:24.04Z" }, - { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341, upload-time = "2026-03-25T20:21:25.177Z" }, - { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159, upload-time = "2026-03-25T20:21:26.364Z" }, - { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290, upload-time = "2026-03-25T20:21:27.46Z" }, - { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141, upload-time = "2026-03-25T20:21:28.492Z" }, - { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847, upload-time = "2026-03-25T20:21:29.386Z" }, - { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088, upload-time = "2026-03-25T20:21:30.677Z" }, - { url = "https://files.pythonhosted.org/packages/07/06/b823a7e818c756d9a7123ba2cda7d07bc2dd32835648d1a7b7b7a05d848d/tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54", size = 155866, upload-time = "2026-03-25T20:21:31.65Z" }, - { url = "https://files.pythonhosted.org/packages/14/6f/12645cf7f08e1a20c7eb8c297c6f11d31c1b50f316a7e7e1e1de6e2e7b7e/tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a", size = 149887, upload-time = "2026-03-25T20:21:33.028Z" }, - { url = "https://files.pythonhosted.org/packages/5c/e0/90637574e5e7212c09099c67ad349b04ec4d6020324539297b634a0192b0/tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897", size = 243704, upload-time = "2026-03-25T20:21:34.51Z" }, - { url = "https://files.pythonhosted.org/packages/10/8f/d3ddb16c5a4befdf31a23307f72828686ab2096f068eaf56631e136c1fdd/tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f", size = 251628, upload-time = "2026-03-25T20:21:36.012Z" }, - { url = "https://files.pythonhosted.org/packages/e3/f1/dbeeb9116715abee2485bf0a12d07a8f31af94d71608c171c45f64c0469d/tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d", size = 247180, upload-time = "2026-03-25T20:21:37.136Z" }, - { url = "https://files.pythonhosted.org/packages/d3/74/16336ffd19ed4da28a70959f92f506233bd7cfc2332b20bdb01591e8b1d1/tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5", size = 251674, upload-time = "2026-03-25T20:21:38.298Z" }, - { url = "https://files.pythonhosted.org/packages/16/f9/229fa3434c590ddf6c0aa9af64d3af4b752540686cace29e6281e3458469/tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd", size = 97976, upload-time = "2026-03-25T20:21:39.316Z" }, - { url = "https://files.pythonhosted.org/packages/6a/1e/71dfd96bcc1c775420cb8befe7a9d35f2e5b1309798f009dca17b7708c1e/tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36", size = 108755, upload-time = "2026-03-25T20:21:40.248Z" }, - { url = "https://files.pythonhosted.org/packages/83/7a/d34f422a021d62420b78f5c538e5b102f62bea616d1d75a13f0a88acb04a/tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd", size = 95265, upload-time = "2026-03-25T20:21:41.219Z" }, - { url = "https://files.pythonhosted.org/packages/3c/fb/9a5c8d27dbab540869f7c1f8eb0abb3244189ce780ba9cd73f3770662072/tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf", size = 155726, upload-time = "2026-03-25T20:21:42.23Z" }, - { url = "https://files.pythonhosted.org/packages/62/05/d2f816630cc771ad836af54f5001f47a6f611d2d39535364f148b6a92d6b/tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac", size = 149859, upload-time = "2026-03-25T20:21:43.386Z" }, - { url = "https://files.pythonhosted.org/packages/ce/48/66341bdb858ad9bd0ceab5a86f90eddab127cf8b046418009f2125630ecb/tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662", size = 244713, upload-time = "2026-03-25T20:21:44.474Z" }, - { url = "https://files.pythonhosted.org/packages/df/6d/c5fad00d82b3c7a3ab6189bd4b10e60466f22cfe8a08a9394185c8a8111c/tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853", size = 252084, upload-time = "2026-03-25T20:21:45.62Z" }, - { url = "https://files.pythonhosted.org/packages/00/71/3a69e86f3eafe8c7a59d008d245888051005bd657760e96d5fbfb0b740c2/tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15", size = 247973, upload-time = "2026-03-25T20:21:46.937Z" }, - { url = "https://files.pythonhosted.org/packages/67/50/361e986652847fec4bd5e4a0208752fbe64689c603c7ae5ea7cb16b1c0ca/tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba", size = 256223, upload-time = "2026-03-25T20:21:48.467Z" }, - { url = "https://files.pythonhosted.org/packages/8c/9a/b4173689a9203472e5467217e0154b00e260621caa227b6fa01feab16998/tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6", size = 98973, upload-time = "2026-03-25T20:21:49.526Z" }, - { url = "https://files.pythonhosted.org/packages/14/58/640ac93bf230cd27d002462c9af0d837779f8773bc03dee06b5835208214/tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7", size = 109082, upload-time = "2026-03-25T20:21:50.506Z" }, - { url = "https://files.pythonhosted.org/packages/d5/2f/702d5e05b227401c1068f0d386d79a589bb12bf64c3d2c72ce0631e3bc49/tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232", size = 96490, upload-time = "2026-03-25T20:21:51.474Z" }, - { url = "https://files.pythonhosted.org/packages/45/4b/b877b05c8ba62927d9865dd980e34a755de541eb65fffba52b4cc495d4d2/tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4", size = 164263, upload-time = "2026-03-25T20:21:52.543Z" }, - { url = "https://files.pythonhosted.org/packages/24/79/6ab420d37a270b89f7195dec5448f79400d9e9c1826df982f3f8e97b24fd/tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c", size = 160736, upload-time = "2026-03-25T20:21:53.674Z" }, - { url = "https://files.pythonhosted.org/packages/02/e0/3630057d8eb170310785723ed5adcdfb7d50cb7e6455f85ba8a3deed642b/tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d", size = 270717, upload-time = "2026-03-25T20:21:55.129Z" }, - { url = "https://files.pythonhosted.org/packages/7a/b4/1613716072e544d1a7891f548d8f9ec6ce2faf42ca65acae01d76ea06bb0/tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41", size = 278461, upload-time = "2026-03-25T20:21:56.228Z" }, - { url = "https://files.pythonhosted.org/packages/05/38/30f541baf6a3f6df77b3df16b01ba319221389e2da59427e221ef417ac0c/tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c", size = 274855, upload-time = "2026-03-25T20:21:57.653Z" }, - { url = "https://files.pythonhosted.org/packages/77/a3/ec9dd4fd2c38e98de34223b995a3b34813e6bdadf86c75314c928350ed14/tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f", size = 283144, upload-time = "2026-03-25T20:21:59.089Z" }, - { url = "https://files.pythonhosted.org/packages/ef/be/605a6261cac79fba2ec0c9827e986e00323a1945700969b8ee0b30d85453/tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8", size = 108683, upload-time = "2026-03-25T20:22:00.214Z" }, - { url = "https://files.pythonhosted.org/packages/12/64/da524626d3b9cc40c168a13da8335fe1c51be12c0a63685cc6db7308daae/tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26", size = 121196, upload-time = "2026-03-25T20:22:01.169Z" }, - { url = "https://files.pythonhosted.org/packages/5a/cd/e80b62269fc78fc36c9af5a6b89c835baa8af28ff5ad28c7028d60860320/tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396", size = 100393, upload-time = "2026-03-25T20:22:02.137Z" }, - { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, -] - -[[package]] -name = "typing-extensions" -version = "4.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, -] - -[[package]] -name = "typing-inspection" -version = "0.4.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a3/26/b09b8010994eccc3c09092e6b34058f36a460eea2d4c3e8b910c695975a0/typing_inspection-0.4.4.tar.gz", hash = "sha256:547274fa6b0a561ccf549cc9524b999a578e737d015d8709d021f9d0d13bea47", size = 76928, upload-time = "2026-08-12T12:37:25.997Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl", hash = "sha256:65b8397ba37ccbce054456aaccddfc91e6e3083c92824df348d96ca832f3f147", size = 14750, upload-time = "2026-08-12T12:37:24.648Z" }, -] diff --git a/package.json b/package.json deleted file mode 100644 index 2d2e9a37..00000000 --- a/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "e2b-code-interpreter-root", - "private": true, - "scripts": { - "version": "pnpm changeset version && pnpm run -r postVersion", - "publish": "pnpm changeset publish && pnpm run -r postPublish", - "rm-node-modules": "find . -name 'node_modules' -type d -prune -exec rm -rf '{}' +", - "lint": "pnpm --if-present --recursive run lint", - "format": "pnpm --if-present --recursive run format", - "changeset": "pnpx @changesets/cli" - }, - "packageManager": "pnpm@10.34.5", - "devDependencies": { - "@changesets/read": "^0.6.2", - "changeset": "^0.2.6" - }, - "engines": { - "pnpm": ">=10.16.0 <11" - } -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index a1e5e3a7..00000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,1573 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: true - -importers: - - .: - devDependencies: - '@changesets/read': - specifier: ^0.6.2 - version: 0.6.7 - changeset: - specifier: ^0.2.6 - version: 0.2.6 - - chart_data_extractor: - devDependencies: - '@typescript-eslint/eslint-plugin': - specifier: ^7.11.0 - version: 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@7.0.2))(eslint@8.57.1)(typescript@7.0.2) - '@typescript-eslint/parser': - specifier: ^7.11.0 - version: 7.18.0(eslint@8.57.1)(typescript@7.0.2) - eslint: - specifier: ^8.57.1 - version: 8.57.1 - - template: {} - - tests: {} - -packages: - - '@babel/runtime@7.29.7': - resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} - engines: {node: '>=6.9.0'} - - '@changesets/errors@0.2.0': - resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} - - '@changesets/git@3.0.4': - resolution: {integrity: sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==} - - '@changesets/logger@0.1.1': - resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==} - - '@changesets/parse@0.4.3': - resolution: {integrity: sha512-ZDmNc53+dXdWEv7fqIUSgRQOLYoUom5Z40gmLgmATmYR9NbL6FJJHwakcCpzaeCy+1D0m0n7mT4jj2B/MQPl7A==} - - '@changesets/read@0.6.7': - resolution: {integrity: sha512-D1G4AUYGrBEk8vj8MGwf75k9GpN6XL3wg8i42P2jZZwFLXnlr2Pn7r9yuQNbaMCarP7ZQWNJbV6XLeysAIMhTA==} - - '@changesets/types@4.1.0': - resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==} - - '@changesets/types@6.1.0': - resolution: {integrity: sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==} - - '@eslint-community/eslint-utils@4.10.1': - resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.12.2': - resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/eslintrc@2.1.4': - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@eslint/js@8.57.1': - resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@humanwhocodes/config-array@0.13.0': - resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - - '@humanwhocodes/object-schema@2.0.3': - resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} - deprecated: Use @eslint/object-schema instead - - '@manypkg/find-root@1.1.0': - resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} - - '@manypkg/get-packages@1.1.3': - resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} - - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - - '@types/node@12.20.55': - resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - - '@typescript-eslint/eslint-plugin@7.18.0': - resolution: {integrity: sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - '@typescript-eslint/parser': ^7.0.0 - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/parser@7.18.0': - resolution: {integrity: sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/scope-manager@7.18.0': - resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@typescript-eslint/type-utils@7.18.0': - resolution: {integrity: sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/types@7.18.0': - resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@typescript-eslint/typescript-estree@7.18.0': - resolution: {integrity: sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/utils@7.18.0': - resolution: {integrity: sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - - '@typescript-eslint/visitor-keys@7.18.0': - resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@typescript/typescript-aix-ppc64@7.0.2': - resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==} - engines: {node: '>=16.20.0'} - cpu: [ppc64] - os: [aix] - - '@typescript/typescript-darwin-arm64@7.0.2': - resolution: {integrity: sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [darwin] - - '@typescript/typescript-darwin-x64@7.0.2': - resolution: {integrity: sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [darwin] - - '@typescript/typescript-freebsd-arm64@7.0.2': - resolution: {integrity: sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [freebsd] - - '@typescript/typescript-freebsd-x64@7.0.2': - resolution: {integrity: sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [freebsd] - - '@typescript/typescript-linux-arm64@7.0.2': - resolution: {integrity: sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [linux] - - '@typescript/typescript-linux-arm@7.0.2': - resolution: {integrity: sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==} - engines: {node: '>=16.20.0'} - cpu: [arm] - os: [linux] - - '@typescript/typescript-linux-loong64@7.0.2': - resolution: {integrity: sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==} - engines: {node: '>=16.20.0'} - cpu: [loong64] - os: [linux] - - '@typescript/typescript-linux-mips64el@7.0.2': - resolution: {integrity: sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==} - engines: {node: '>=16.20.0'} - cpu: [mips64el] - os: [linux] - - '@typescript/typescript-linux-ppc64@7.0.2': - resolution: {integrity: sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==} - engines: {node: '>=16.20.0'} - cpu: [ppc64] - os: [linux] - - '@typescript/typescript-linux-riscv64@7.0.2': - resolution: {integrity: sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==} - engines: {node: '>=16.20.0'} - cpu: [riscv64] - os: [linux] - - '@typescript/typescript-linux-s390x@7.0.2': - resolution: {integrity: sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==} - engines: {node: '>=16.20.0'} - cpu: [s390x] - os: [linux] - - '@typescript/typescript-linux-x64@7.0.2': - resolution: {integrity: sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [linux] - - '@typescript/typescript-netbsd-arm64@7.0.2': - resolution: {integrity: sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [netbsd] - - '@typescript/typescript-netbsd-x64@7.0.2': - resolution: {integrity: sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [netbsd] - - '@typescript/typescript-openbsd-arm64@7.0.2': - resolution: {integrity: sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [openbsd] - - '@typescript/typescript-openbsd-x64@7.0.2': - resolution: {integrity: sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [openbsd] - - '@typescript/typescript-sunos-x64@7.0.2': - resolution: {integrity: sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [sunos] - - '@typescript/typescript-win32-arm64@7.0.2': - resolution: {integrity: sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [win32] - - '@typescript/typescript-win32-x64@7.0.2': - resolution: {integrity: sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [win32] - - '@ungap/structured-clone@1.3.3': - resolution: {integrity: sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==} - - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn@8.18.0: - resolution: {integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==} - engines: {node: '>=0.4.0'} - hasBin: true - - ajv@6.15.0: - resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - better-path-resolve@1.0.0: - resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} - engines: {node: '>=4'} - - brace-expansion@1.1.18: - resolution: {integrity: sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==} - - brace-expansion@2.1.4: - resolution: {integrity: sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - changeset@0.2.6: - resolution: {integrity: sha512-d21ym9zLPOKMVhIa8ulJo5IV3QR2NNdK6BWuwg48qJA0XSQaMeDjo1UGThcTn7YDmU08j3UpKyFNvb3zplk8mw==} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - - dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - - doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint@8.57.1: - resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. - hasBin: true - - espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - - esquery@1.7.0: - resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} - engines: {node: '>=0.10'} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - extendable-error@0.1.7: - resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - - fastq@1.20.1: - resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} - - file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} - - flatted@3.4.4: - resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} - - fs-extra@7.0.1: - resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} - engines: {node: '>=6 <7 || >=8'} - - fs-extra@8.1.0: - resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} - engines: {node: '>=6 <7 || >=8'} - - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - - globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} - - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - - is-subdir@1.2.0: - resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} - engines: {node: '>=4'} - - is-windows@1.0.2: - resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} - engines: {node: '>=0.10.0'} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - js-yaml@3.15.2: - resolution: {integrity: sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==} - hasBin: true - - js-yaml@4.3.2: - resolution: {integrity: sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==} - hasBin: true - - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - - jsonfile@4.0.0: - resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - - locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} - - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - - minimatch@3.1.5: - resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - - minimatch@9.0.9: - resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} - engines: {node: '>=16 || 14 >=14.17'} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - - p-filter@2.1.0: - resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} - engines: {node: '>=8'} - - p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - - p-map@2.1.0: - resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} - engines: {node: '>=6'} - - p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@2.3.2: - resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} - engines: {node: '>=8.6'} - - pify@4.0.1: - resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} - engines: {node: '>=6'} - - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - read-yaml-file@1.1.0: - resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} - engines: {node: '>=6'} - - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - - reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - - semver@7.8.5: - resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} - engines: {node: '>=10'} - hasBin: true - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - - spawndamnit@3.0.1: - resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} - - sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - ts-api-utils@1.4.3: - resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} - engines: {node: '>=16'} - peerDependencies: - typescript: '>=4.2.0' - - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - - typescript@7.0.2: - resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==} - engines: {node: '>=16.20.0'} - hasBin: true - - udc@1.0.1: - resolution: {integrity: sha512-jv+D9de1flsum5QkFtBdjyppCQAdz9kTck/0xST5Vx48T9LL2BYnw0Iw77dSKDQ9KZ/PS3qPO1vfXHDpLZlxcQ==} - - underscore@1.13.8: - resolution: {integrity: sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==} - - universalify@0.1.2: - resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} - engines: {node: '>= 4.0.0'} - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - -snapshots: - - '@babel/runtime@7.29.7': {} - - '@changesets/errors@0.2.0': - dependencies: - extendable-error: 0.1.7 - - '@changesets/git@3.0.4': - dependencies: - '@changesets/errors': 0.2.0 - '@manypkg/get-packages': 1.1.3 - is-subdir: 1.2.0 - micromatch: 4.0.8 - spawndamnit: 3.0.1 - - '@changesets/logger@0.1.1': - dependencies: - picocolors: 1.1.1 - - '@changesets/parse@0.4.3': - dependencies: - '@changesets/types': 6.1.0 - js-yaml: 4.3.2 - - '@changesets/read@0.6.7': - dependencies: - '@changesets/git': 3.0.4 - '@changesets/logger': 0.1.1 - '@changesets/parse': 0.4.3 - '@changesets/types': 6.1.0 - fs-extra: 7.0.1 - p-filter: 2.1.0 - picocolors: 1.1.1 - - '@changesets/types@4.1.0': {} - - '@changesets/types@6.1.0': {} - - '@eslint-community/eslint-utils@4.10.1(eslint@8.57.1)': - dependencies: - eslint: 8.57.1 - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.12.2': {} - - '@eslint/eslintrc@2.1.4': - dependencies: - ajv: 6.15.0 - debug: 4.4.3 - espree: 9.6.1 - globals: 13.24.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.3.2 - minimatch: 3.1.5 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@8.57.1': {} - - '@humanwhocodes/config-array@0.13.0': - dependencies: - '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.3 - minimatch: 3.1.5 - transitivePeerDependencies: - - supports-color - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/object-schema@2.0.3': {} - - '@manypkg/find-root@1.1.0': - dependencies: - '@babel/runtime': 7.29.7 - '@types/node': 12.20.55 - find-up: 4.1.0 - fs-extra: 8.1.0 - - '@manypkg/get-packages@1.1.3': - dependencies: - '@babel/runtime': 7.29.7 - '@changesets/types': 4.1.0 - '@manypkg/find-root': 1.1.0 - fs-extra: 8.1.0 - globby: 11.1.0 - read-yaml-file: 1.1.0 - - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.20.1 - - '@types/node@12.20.55': {} - - '@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@7.0.2))(eslint@8.57.1)(typescript@7.0.2)': - dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@7.0.2) - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/type-utils': 7.18.0(eslint@8.57.1)(typescript@7.0.2) - '@typescript-eslint/utils': 7.18.0(eslint@8.57.1)(typescript@7.0.2) - '@typescript-eslint/visitor-keys': 7.18.0 - eslint: 8.57.1 - graphemer: 1.4.0 - ignore: 5.3.2 - natural-compare: 1.4.0 - ts-api-utils: 1.4.3(typescript@7.0.2) - optionalDependencies: - typescript: 7.0.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@7.0.2)': - dependencies: - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/typescript-estree': 7.18.0(typescript@7.0.2) - '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.4.3 - eslint: 8.57.1 - optionalDependencies: - typescript: 7.0.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@7.18.0': - dependencies: - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/visitor-keys': 7.18.0 - - '@typescript-eslint/type-utils@7.18.0(eslint@8.57.1)(typescript@7.0.2)': - dependencies: - '@typescript-eslint/typescript-estree': 7.18.0(typescript@7.0.2) - '@typescript-eslint/utils': 7.18.0(eslint@8.57.1)(typescript@7.0.2) - debug: 4.4.3 - eslint: 8.57.1 - ts-api-utils: 1.4.3(typescript@7.0.2) - optionalDependencies: - typescript: 7.0.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@7.18.0': {} - - '@typescript-eslint/typescript-estree@7.18.0(typescript@7.0.2)': - dependencies: - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.4.3 - globby: 11.1.0 - is-glob: 4.0.3 - minimatch: 9.0.9 - semver: 7.8.5 - ts-api-utils: 1.4.3(typescript@7.0.2) - optionalDependencies: - typescript: 7.0.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@7.18.0(eslint@8.57.1)(typescript@7.0.2)': - dependencies: - '@eslint-community/eslint-utils': 4.10.1(eslint@8.57.1) - '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/typescript-estree': 7.18.0(typescript@7.0.2) - eslint: 8.57.1 - transitivePeerDependencies: - - supports-color - - typescript - - '@typescript-eslint/visitor-keys@7.18.0': - dependencies: - '@typescript-eslint/types': 7.18.0 - eslint-visitor-keys: 3.4.3 - - '@typescript/typescript-aix-ppc64@7.0.2': - optional: true - - '@typescript/typescript-darwin-arm64@7.0.2': - optional: true - - '@typescript/typescript-darwin-x64@7.0.2': - optional: true - - '@typescript/typescript-freebsd-arm64@7.0.2': - optional: true - - '@typescript/typescript-freebsd-x64@7.0.2': - optional: true - - '@typescript/typescript-linux-arm64@7.0.2': - optional: true - - '@typescript/typescript-linux-arm@7.0.2': - optional: true - - '@typescript/typescript-linux-loong64@7.0.2': - optional: true - - '@typescript/typescript-linux-mips64el@7.0.2': - optional: true - - '@typescript/typescript-linux-ppc64@7.0.2': - optional: true - - '@typescript/typescript-linux-riscv64@7.0.2': - optional: true - - '@typescript/typescript-linux-s390x@7.0.2': - optional: true - - '@typescript/typescript-linux-x64@7.0.2': - optional: true - - '@typescript/typescript-netbsd-arm64@7.0.2': - optional: true - - '@typescript/typescript-netbsd-x64@7.0.2': - optional: true - - '@typescript/typescript-openbsd-arm64@7.0.2': - optional: true - - '@typescript/typescript-openbsd-x64@7.0.2': - optional: true - - '@typescript/typescript-sunos-x64@7.0.2': - optional: true - - '@typescript/typescript-win32-arm64@7.0.2': - optional: true - - '@typescript/typescript-win32-x64@7.0.2': - optional: true - - '@ungap/structured-clone@1.3.3': {} - - acorn-jsx@5.3.2(acorn@8.18.0): - dependencies: - acorn: 8.18.0 - - acorn@8.18.0: {} - - ajv@6.15.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - ansi-regex@5.0.1: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - argparse@1.0.10: - dependencies: - sprintf-js: 1.0.3 - - argparse@2.0.1: {} - - array-union@2.1.0: {} - - balanced-match@1.0.2: {} - - better-path-resolve@1.0.0: - dependencies: - is-windows: 1.0.2 - - brace-expansion@1.1.18: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@2.1.4: - dependencies: - balanced-match: 1.0.2 - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - callsites@3.1.0: {} - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - changeset@0.2.6: - dependencies: - udc: 1.0.1 - underscore: 1.13.8 - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - - concat-map@0.0.1: {} - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - deep-is@0.1.4: {} - - dir-glob@3.0.1: - dependencies: - path-type: 4.0.0 - - doctrine@3.0.0: - dependencies: - esutils: 2.0.3 - - escape-string-regexp@4.0.0: {} - - eslint-scope@7.2.2: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint@8.57.1: - dependencies: - '@eslint-community/eslint-utils': 4.10.1(eslint@8.57.1) - '@eslint-community/regexpp': 4.12.2 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.1 - '@humanwhocodes/config-array': 0.13.0 - '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.3.3 - ajv: 6.15.0 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.3 - doctrine: 3.0.0 - escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - esquery: 1.7.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.3.2 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.5 - natural-compare: 1.4.0 - optionator: 0.9.4 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - - espree@9.6.1: - dependencies: - acorn: 8.18.0 - acorn-jsx: 5.3.2(acorn@8.18.0) - eslint-visitor-keys: 3.4.3 - - esprima@4.0.1: {} - - esquery@1.7.0: - dependencies: - estraverse: 5.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@5.3.0: {} - - esutils@2.0.3: {} - - extendable-error@0.1.7: {} - - fast-deep-equal@3.1.3: {} - - fast-glob@3.3.3: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - - fastq@1.20.1: - dependencies: - reusify: 1.1.0 - - file-entry-cache@6.0.1: - dependencies: - flat-cache: 3.2.0 - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - find-up@4.1.0: - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flat-cache@3.2.0: - dependencies: - flatted: 3.4.4 - keyv: 4.5.4 - rimraf: 3.0.2 - - flatted@3.4.4: {} - - fs-extra@7.0.1: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - - fs-extra@8.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - - fs.realpath@1.0.0: {} - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.5 - once: 1.4.0 - path-is-absolute: 1.0.1 - - globals@13.24.0: - dependencies: - type-fest: 0.20.2 - - globby@11.1.0: - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.3 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - - graceful-fs@4.2.11: {} - - graphemer@1.4.0: {} - - has-flag@4.0.0: {} - - ignore@5.3.2: {} - - import-fresh@3.3.1: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - - imurmurhash@0.1.4: {} - - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - - inherits@2.0.4: {} - - is-extglob@2.1.1: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-number@7.0.0: {} - - is-path-inside@3.0.3: {} - - is-subdir@1.2.0: - dependencies: - better-path-resolve: 1.0.0 - - is-windows@1.0.2: {} - - isexe@2.0.0: {} - - js-yaml@3.15.2: - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - - js-yaml@4.3.2: - dependencies: - argparse: 2.0.1 - - json-buffer@3.0.1: {} - - json-schema-traverse@0.4.1: {} - - json-stable-stringify-without-jsonify@1.0.1: {} - - jsonfile@4.0.0: - optionalDependencies: - graceful-fs: 4.2.11 - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - - locate-path@5.0.0: - dependencies: - p-locate: 4.1.0 - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - lodash.merge@4.6.2: {} - - merge2@1.4.1: {} - - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.2 - - minimatch@3.1.5: - dependencies: - brace-expansion: 1.1.18 - - minimatch@9.0.9: - dependencies: - brace-expansion: 2.1.4 - - ms@2.1.3: {} - - natural-compare@1.4.0: {} - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - - p-filter@2.1.0: - dependencies: - p-map: 2.1.0 - - p-limit@2.3.0: - dependencies: - p-try: 2.2.0 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@4.1.0: - dependencies: - p-limit: 2.3.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - - p-map@2.1.0: {} - - p-try@2.2.0: {} - - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - - path-exists@4.0.0: {} - - path-is-absolute@1.0.1: {} - - path-key@3.1.1: {} - - path-type@4.0.0: {} - - picocolors@1.1.1: {} - - picomatch@2.3.2: {} - - pify@4.0.1: {} - - prelude-ls@1.2.1: {} - - punycode@2.3.1: {} - - queue-microtask@1.2.3: {} - - read-yaml-file@1.1.0: - dependencies: - graceful-fs: 4.2.11 - js-yaml: 3.15.2 - pify: 4.0.1 - strip-bom: 3.0.0 - - resolve-from@4.0.0: {} - - reusify@1.1.0: {} - - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - - semver@7.8.5: {} - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - signal-exit@4.1.0: {} - - slash@3.0.0: {} - - spawndamnit@3.0.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - - sprintf-js@1.0.3: {} - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-bom@3.0.0: {} - - strip-json-comments@3.1.1: {} - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - text-table@0.2.0: {} - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - ts-api-utils@1.4.3(typescript@7.0.2): - dependencies: - typescript: 7.0.2 - - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - type-fest@0.20.2: {} - - typescript@7.0.2: - optionalDependencies: - '@typescript/typescript-aix-ppc64': 7.0.2 - '@typescript/typescript-darwin-arm64': 7.0.2 - '@typescript/typescript-darwin-x64': 7.0.2 - '@typescript/typescript-freebsd-arm64': 7.0.2 - '@typescript/typescript-freebsd-x64': 7.0.2 - '@typescript/typescript-linux-arm': 7.0.2 - '@typescript/typescript-linux-arm64': 7.0.2 - '@typescript/typescript-linux-loong64': 7.0.2 - '@typescript/typescript-linux-mips64el': 7.0.2 - '@typescript/typescript-linux-ppc64': 7.0.2 - '@typescript/typescript-linux-riscv64': 7.0.2 - '@typescript/typescript-linux-s390x': 7.0.2 - '@typescript/typescript-linux-x64': 7.0.2 - '@typescript/typescript-netbsd-arm64': 7.0.2 - '@typescript/typescript-netbsd-x64': 7.0.2 - '@typescript/typescript-openbsd-arm64': 7.0.2 - '@typescript/typescript-openbsd-x64': 7.0.2 - '@typescript/typescript-sunos-x64': 7.0.2 - '@typescript/typescript-win32-arm64': 7.0.2 - '@typescript/typescript-win32-x64': 7.0.2 - - udc@1.0.1: {} - - underscore@1.13.8: {} - - universalify@0.1.2: {} - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - word-wrap@1.2.5: {} - - wrappy@1.0.2: {} - - yocto-queue@0.1.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml deleted file mode 100644 index 37da767c..00000000 --- a/pnpm-workspace.yaml +++ /dev/null @@ -1,12 +0,0 @@ -packages: - - chart_data_extractor - - template - - tests - -# Only install package versions that have been on the registry for at least -# 3 days, so malicious releases have time to be caught and unpublished. -minimumReleaseAge: 4320 - -# `e2b` is our own SDK — we control its releases, so it doesn't need the delay. -minimumReleaseAgeExclude: - - e2b diff --git a/renovate.json5 b/renovate.json5 index 0a3194fb..889a2fdd 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -5,12 +5,10 @@ { $schema: 'https://docs.renovatebot.com/renovate-schema.json', extends: ['local>e2b-dev/renovate'], - // Keep in sync with `minimumReleaseAge` in pnpm-workspace.yaml (4320 minutes), - // otherwise Renovate proposes versions pnpm then refuses to install. + // Wait three days before using newly released dependencies. minimumReleaseAge: '3 days', packageRules: [ { - // Keep in sync with `minimumReleaseAgeExclude` in pnpm-workspace.yaml. description: 'e2b is our own SDK, so it skips the minimum release age', matchPackageNames: ['e2b'], minimumReleaseAge: null, diff --git a/template/README.md b/template/README.md deleted file mode 100644 index 4f64fabe..00000000 --- a/template/README.md +++ /dev/null @@ -1,124 +0,0 @@ -# Code Interpreter - -## Building the production template - -To build the official `code-interpreter-v1` template from this repo, use -`build_prod.py`. This is the script CI and releases run. - -1. Install the build dependencies: - -``` -pip install -r requirements-dev.txt -``` - -2. Provide your credentials in `.env`: - -``` -E2B_API_KEY=e2b_*** -``` - -3. Build the template: - -``` -python build_prod.py -``` - -Set `SKIP_CACHE=true` to force a clean rebuild that ignores the layer cache: - -``` -SKIP_CACHE=true python build_prod.py -``` - -If you want to customize the Code Interpreter sandbox (e.g.: add a preinstalled package) you can do that by creating a [custom sandbox template](https://e2b.dev/docs/template/quickstart). - -## Creating a custom template - -1. Install E2B SDK - -``` -pip install e2b dotenv -``` - -2. Create a custom sandbox template: - -**template.py** - -```python -from e2b import Template - -template = Template().from_template("code-interpreter-v1") -``` - -3. Create a build script: - -**build.py** - -```python -from dotenv import load_dotenv -from .template import template -from e2b import Template, default_build_logger - -load_dotenv() - -Template.build( - template, - alias="code-interpreter-custom", - cpu_count=2, - memory_mb=2048, - on_build_logs=default_build_logger(), -) -``` - -4. Set your environment variables in a `.env` file (loaded by `load_dotenv()`): - -``` -E2B_API_KEY=e2b_*** -``` - -5. Build the template: - -``` -python build.py -``` - -6. Use the custom template: - -```python -from e2b import Sandbox - -sbx = Sandbox.create(template="code-interpreter-custom") -execution = sbx.run_code("print('Hello, World!')") -print(execution.logs.stdout) -``` - -## Debugging a server that won't start - -The template runs Jupyter and the code-interpreter server as **systemd** -services (`systemd/jupyter.service`, `systemd/code-interpreter.service`). This is -the path CI and production use — note it is *different* from `make -start-template-server`, which runs the Docker `start-up.sh` path. The two can -diverge, so a server that boots fine under Docker may still fail under systemd. - -When a build fails its readiness check (`Waiting for template to be ready ... -timed out`), the real cause is in the service journals. To see them: - -``` -make debug-template -``` - -This builds a debug template (gated on a fixed timeout instead of `/health`, so -it finalizes even while the server is crash-looping), spawns a sandbox, and -prints `systemctl status` + the full `journalctl` for both services. It needs -`template/.env` with your `E2B_API_KEY` and the deps from `requirements-dev.txt`. - -The debug build also applies a systemd drop-in that routes Jupyter's stdout to -the journal (`make_template(debug=True)`). Production builds keep -`StandardOutput=null`, so Jupyter's request/error logs are only captured in the -debug template. - -Inside a running sandbox you can also inspect things directly: - -``` -journalctl -u jupyter -u code-interpreter -systemctl status code-interpreter -``` diff --git a/template/build_ci.py b/template/build_ci.py deleted file mode 100644 index 13c0c311..00000000 --- a/template/build_ci.py +++ /dev/null @@ -1,19 +0,0 @@ -import os -from e2b import Template, default_build_logger -from template import make_template - -build_info = Template.build( - make_template(), - alias=os.environ["E2B_TESTS_TEMPLATE"], - cpu_count=2, - memory_mb=2048, - on_build_logs=default_build_logger(), -) - -template_id = build_info.template_id -print(f"Built template ID: {template_id}") - -github_output = os.getenv("GITHUB_OUTPUT") -if github_output: - with open(github_output, "a", encoding="utf-8") as fh: - fh.write(f"template_id={template_id}\n") diff --git a/template/build_debug.py b/template/build_debug.py deleted file mode 100644 index f4dc63b4..00000000 --- a/template/build_debug.py +++ /dev/null @@ -1,23 +0,0 @@ -import os - -from dotenv import load_dotenv -from e2b import Template, default_build_logger, wait_for_timeout -from template import make_template - -load_dotenv() - -alias = os.getenv("E2B_DEBUG_TEMPLATE", "code-interpreter-debug") - -Template.build( - make_template( - kernels=["python", "javascript"], - ready=wait_for_timeout(60_000), - debug=True, - ), - alias=alias, - cpu_count=2, - memory_mb=2048, - on_build_logs=default_build_logger(min_level="debug"), -) - -print(f"Built debug template: {alias}") diff --git a/template/build_docker.py b/template/build_docker.py deleted file mode 100644 index 7d1438a8..00000000 --- a/template/build_docker.py +++ /dev/null @@ -1,5 +0,0 @@ -from template import make_template -from e2b import Template - -tmp = make_template(kernels=["python", "javascript"], is_docker=True) -print(Template.to_dockerfile(tmp)) diff --git a/template/build_prod.py b/template/build_prod.py deleted file mode 100644 index 1615ebff..00000000 --- a/template/build_prod.py +++ /dev/null @@ -1,18 +0,0 @@ -import os - -from dotenv import load_dotenv -from e2b import Template, default_build_logger -from template import make_template - -load_dotenv() - -skip_cache = os.getenv("SKIP_CACHE", "false").lower() == "true" - -Template.build( - make_template(), - alias="code-interpreter-v1", - cpu_count=2, - memory_mb=2048, - skip_cache=skip_cache, - on_build_logs=default_build_logger(), -) diff --git a/template/build_test.py b/template/build_test.py deleted file mode 100644 index a11128ca..00000000 --- a/template/build_test.py +++ /dev/null @@ -1,13 +0,0 @@ -from dotenv import load_dotenv -from e2b import Template, default_build_logger -from template import make_template - -load_dotenv() - -Template.build( - make_template(kernels=["python", "javascript"]), - alias="code-interpreter-dev", - cpu_count=2, - memory_mb=2048, - on_build_logs=default_build_logger(min_level="debug"), -) diff --git a/template/debug_logs.py b/template/debug_logs.py deleted file mode 100644 index 2cd74aff..00000000 --- a/template/debug_logs.py +++ /dev/null @@ -1,35 +0,0 @@ -import os - -from dotenv import load_dotenv -from e2b import Sandbox - -load_dotenv() - -alias = os.getenv("E2B_DEBUG_TEMPLATE", "code-interpreter-debug") - -sbx = Sandbox.create(template=alias, timeout=600) -print(f"sandbox: {sbx.sandbox_id}") - -CMDS = [ - "systemctl --no-pager status jupyter || true", - "systemctl --no-pager status code-interpreter || true", - "journalctl --no-pager -u jupyter || true", - "journalctl --no-pager -u code-interpreter || true", - "curl --unix-socket /run/e2b-jupyter/server.sock -s --max-time 3 -o /dev/null -w 'jupyter socket -> %{http_code}\\n' http://localhost/api/status || true", - "curl -s --max-time 3 -o /dev/null -w 'server :49999 -> %{http_code}\\n' http://localhost:49999/health || true", -] - -try: - for cmd in CMDS: - print(f"\n===== $ {cmd} =====") - try: - result = sbx.commands.run(f"sudo bash -lc {cmd!r}", timeout=60) - if result.stdout: - print(result.stdout) - if result.stderr: - print("[stderr]", result.stderr) - except Exception as e: - # Keep going so one slow/failed command doesn't skip the rest. - print(f"[command failed] {e}") -finally: - sbx.kill() diff --git a/template/ipython_kernel_config.py b/template/ipython_kernel_config.py deleted file mode 100644 index 26900faa..00000000 --- a/template/ipython_kernel_config.py +++ /dev/null @@ -1,969 +0,0 @@ -# Configuration file for ipython-kernel. - -c = get_config() # noqa - -## Set the color scheme (NoColor, Neutral, Linux, or LightBG). -# Choices: any of ['Neutral', 'NoColor', 'LightBG', 'Linux'] (case-insensitive) -# Default: 'Neutral' -c.InteractiveShell.colors = "NoColor" - - -# ------------------------------------------------------------------------------ -# ConnectionFileMixin(LoggingConfigurable) configuration -# ------------------------------------------------------------------------------ -## Mixin for configurable classes that work with connection files - -## JSON file in which to store connection info [default: kernel-.json] -# -# This file will contain the IP, ports, and authentication key needed to connect -# clients to this kernel. By default, this file will be created in the security dir -# of the current profile, but can be specified by absolute path. -# Default: '' -# c.ConnectionFileMixin.connection_file = '' - -## set the control (ROUTER) port [default: random] -# Default: 0 -# c.ConnectionFileMixin.control_port = 0 - -## set the heartbeat port [default: random] -# Default: 0 -# c.ConnectionFileMixin.hb_port = 0 - -## set the iopub (PUB) port [default: random] -# Default: 0 -# c.ConnectionFileMixin.iopub_port = 0 - -## Set the kernel's IP address [default localhost]. -# If the IP address is something other than localhost, then -# Consoles on other machines will be able to connect -# to the Kernel, so be careful! -# Default: '' -# c.ConnectionFileMixin.ip = '' - -## set the shell (ROUTER) port [default: random] -# Default: 0 -# c.ConnectionFileMixin.shell_port = 0 - -## set the stdin (ROUTER) port [default: random] -# Default: 0 -# c.ConnectionFileMixin.stdin_port = 0 - -# Choices: any of ['tcp', 'ipc'] (case-insensitive) -# Default: 'tcp' -# c.ConnectionFileMixin.transport = 'tcp' - -# ------------------------------------------------------------------------------ -# InteractiveShellApp(Configurable) configuration -# ------------------------------------------------------------------------------ -## A Mixin for applications that start InteractiveShell instances. -# -# Provides configurables for loading extensions and executing files -# as part of configuring a Shell environment. -# -# The following methods should be called by the :meth:`initialize` method -# of the subclass: -# -# - :meth:`init_path` -# - :meth:`init_shell` (to be implemented by the subclass) -# - :meth:`init_gui_pylab` -# - :meth:`init_extensions` -# - :meth:`init_code` - -## Execute the given command string. -# Default: '' -# c.InteractiveShellApp.code_to_run = '' - -## Run the file referenced by the PYTHONSTARTUP environment -# variable at IPython startup. -# Default: True -# c.InteractiveShellApp.exec_PYTHONSTARTUP = True - -## List of files to run at IPython startup. -# Default: [] -# c.InteractiveShellApp.exec_files = [] - -## lines of code to run at IPython startup. -# Default: [] -# c.InteractiveShellApp.exec_lines = [] - -## A list of dotted module names of IPython extensions to load. -# Default: [] -# c.InteractiveShellApp.extensions = [] - -## Dotted module name(s) of one or more IPython extensions to load. -# -# For specifying extra extensions to load on the command-line. -# -# .. versionadded:: 7.10 -# Default: [] -# c.InteractiveShellApp.extra_extensions = [] - -## A file to be run -# Default: '' -# c.InteractiveShellApp.file_to_run = '' - -## Enable GUI event loop integration with any of ('asyncio', 'glut', 'gtk', -# 'gtk2', 'gtk3', 'gtk4', 'osx', 'pyglet', 'qt', 'qt5', 'qt6', 'tk', 'wx', -# 'gtk2', 'qt4'). -# Choices: any of ['asyncio', 'glut', 'gtk', 'gtk2', 'gtk3', 'gtk4', 'osx', 'pyglet', 'qt', 'qt5', 'qt6', 'tk', 'wx', 'gtk2', 'qt4'] (case-insensitive) or None -# Default: None -# c.InteractiveShellApp.gui = None - -## Should variables loaded at startup (by startup files, exec_lines, etc.) -# be hidden from tools like %who? -# Default: True -# c.InteractiveShellApp.hide_initial_ns = True - -## If True, IPython will not add the current working directory to sys.path. -# When False, the current working directory is added to sys.path, allowing imports -# of modules defined in the current directory. -# Default: False -# c.InteractiveShellApp.ignore_cwd = False - -## Configure matplotlib for interactive use with -# the default matplotlib backend. -# Choices: any of ['auto', 'agg', 'gtk', 'gtk3', 'gtk4', 'inline', 'ipympl', 'nbagg', 'notebook', 'osx', 'pdf', 'ps', 'qt', 'qt4', 'qt5', 'qt6', 'svg', 'tk', 'webagg', 'widget', 'wx'] (case-insensitive) or None -# Default: None -# c.InteractiveShellApp.matplotlib = None - -## Run the module as a script. -# Default: '' -# c.InteractiveShellApp.module_to_run = '' - -## Pre-load matplotlib and numpy for interactive use, -# selecting a particular matplotlib backend and loop integration. -# Choices: any of ['auto', 'agg', 'gtk', 'gtk3', 'gtk4', 'inline', 'ipympl', 'nbagg', 'notebook', 'osx', 'pdf', 'ps', 'qt', 'qt4', 'qt5', 'qt6', 'svg', 'tk', 'webagg', 'widget', 'wx'] (case-insensitive) or None -# Default: None -# c.InteractiveShellApp.pylab = None - -## If true, IPython will populate the user namespace with numpy, pylab, etc. -# and an ``import *`` is done from numpy and pylab, when using pylab mode. -# -# When False, pylab mode should not import any names into the user -# namespace. -# Default: True -# c.InteractiveShellApp.pylab_import_all = True - -## Reraise exceptions encountered loading IPython extensions? -# Default: False -# c.InteractiveShellApp.reraise_ipython_extension_failures = False - -# ------------------------------------------------------------------------------ -# Application(SingletonConfigurable) configuration -# ------------------------------------------------------------------------------ -## This is an application. - -## The date format used by logging formatters for %(asctime)s -# Default: '%Y-%m-%d %H:%M:%S' -# c.Application.log_datefmt = '%Y-%m-%d %H:%M:%S' - -## The Logging format template -# Default: '[%(name)s]%(highlevel)s %(message)s' -# c.Application.log_format = '[%(name)s]%(highlevel)s %(message)s' - -## Set the log level by value or name. -# Choices: any of [0, 10, 20, 30, 40, 50, 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL'] -# Default: 30 -# c.Application.log_level = 30 - -## Configure additional log handlers. -# -# The default stderr logs handler is configured by the log_level, log_datefmt -# and log_format settings. -# -# This configuration can be used to configure additional handlers (e.g. to -# output the log to a file) or for finer control over the default handlers. -# -# If provided this should be a logging configuration dictionary, for more -# information see: -# https://docs.python.org/3/library/logging.config.html#logging-config- -# dictschema -# -# This dictionary is merged with the base logging configuration which defines -# the following: -# -# * A logging formatter intended for interactive use called -# ``console``. -# * A logging handler that writes to stderr called -# ``console`` which uses the formatter ``console``. -# * A logger with the name of this application set to ``DEBUG`` -# level. -# -# This example adds a new handler that writes to a file: -# -# .. code-block:: python -# -# c.Application.logging_config = { -# "handlers": { -# "file": { -# "class": "logging.FileHandler", -# "level": "DEBUG", -# "filename": "", -# } -# }, -# "loggers": { -# "": { -# "level": "DEBUG", -# # NOTE: if you don't list the default "console" -# # handler here then it will be disabled -# "handlers": ["console", "file"], -# }, -# }, -# } -# Default: {} -# c.Application.logging_config = {} - -## Instead of starting the Application, dump configuration to stdout -# Default: False -# c.Application.show_config = False - -## Instead of starting the Application, dump configuration to stdout (as JSON) -# Default: False -# c.Application.show_config_json = False - -# ------------------------------------------------------------------------------ -# BaseIPythonApplication(Application) configuration -# ------------------------------------------------------------------------------ -# Default: False -# c.BaseIPythonApplication.add_ipython_dir_to_sys_path = False - -## Whether to create profile dir if it doesn't exist -# Default: False -# c.BaseIPythonApplication.auto_create = False - -## Whether to install the default config files into the profile dir. -# If a new profile is being created, and IPython contains config files for that -# profile, then they will be staged into the new directory. Otherwise, -# default config files will be automatically generated. -# Default: False -# c.BaseIPythonApplication.copy_config_files = False - -## Path to an extra config file to load. -# -# If specified, load this config file in addition to any other IPython -# config. -# Default: '' -# c.BaseIPythonApplication.extra_config_file = '' - -## The name of the IPython directory. This directory is used for logging -# configuration (through profiles), history storage, etc. The default is usually -# $HOME/.ipython. This option can also be specified through the environment -# variable IPYTHONDIR. -# Default: '' -# c.BaseIPythonApplication.ipython_dir = '' - -## The date format used by logging formatters for %(asctime)s -# See also: Application.log_datefmt -# c.BaseIPythonApplication.log_datefmt = '%Y-%m-%d %H:%M:%S' - -## The Logging format template -# See also: Application.log_format -# c.BaseIPythonApplication.log_format = '[%(name)s]%(highlevel)s %(message)s' - -## Set the log level by value or name. -# See also: Application.log_level -# c.BaseIPythonApplication.log_level = 30 - -## -# See also: Application.logging_config -# c.BaseIPythonApplication.logging_config = {} - -## Whether to overwrite existing config files when copying -# Default: False -# c.BaseIPythonApplication.overwrite = False - -## The IPython profile to use. -# Default: 'default' -# c.BaseIPythonApplication.profile = 'default' - -## Instead of starting the Application, dump configuration to stdout -# See also: Application.show_config -# c.BaseIPythonApplication.show_config = False - -## Instead of starting the Application, dump configuration to stdout (as JSON) -# See also: Application.show_config_json -# c.BaseIPythonApplication.show_config_json = False - -## Create a massive crash report when IPython encounters what may be an -# internal error. The default is to append a short message to the -# usual traceback -# Default: False -# c.BaseIPythonApplication.verbose_crash = False - -# ------------------------------------------------------------------------------ -# IPKernelApp(BaseIPythonApplication, InteractiveShellApp, ConnectionFileMixin) configuration -# ------------------------------------------------------------------------------ -## The IPYKernel application class. - -# See also: BaseIPythonApplication.add_ipython_dir_to_sys_path -# c.IPKernelApp.add_ipython_dir_to_sys_path = False - -## Whether to create profile dir if it doesn't exist -# See also: BaseIPythonApplication.auto_create -# c.IPKernelApp.auto_create = False - -## Attempt to capture and forward low-level output, e.g. produced by Extension -# libraries. -# Default: True -# c.IPKernelApp.capture_fd_output = True - -## Execute the given command string. -# See also: InteractiveShellApp.code_to_run -# c.IPKernelApp.code_to_run = '' - -## JSON file in which to store connection info [default: kernel-.json] -# See also: ConnectionFileMixin.connection_file -# c.IPKernelApp.connection_file = '' - -## set the control (ROUTER) port [default: random] -# See also: ConnectionFileMixin.control_port -# c.IPKernelApp.control_port = 0 - -## Whether to install the default config files into the profile dir. -# See also: BaseIPythonApplication.copy_config_files -# c.IPKernelApp.copy_config_files = False - -## The importstring for the DisplayHook factory -# Default: 'ipykernel.displayhook.ZMQDisplayHook' -# c.IPKernelApp.displayhook_class = 'ipykernel.displayhook.ZMQDisplayHook' - -## Run the file referenced by the PYTHONSTARTUP environment -# See also: InteractiveShellApp.exec_PYTHONSTARTUP -# c.IPKernelApp.exec_PYTHONSTARTUP = True - -## List of files to run at IPython startup. -# See also: InteractiveShellApp.exec_files -# c.IPKernelApp.exec_files = [] - -## lines of code to run at IPython startup. -# See also: InteractiveShellApp.exec_lines -# c.IPKernelApp.exec_lines = [] - -## A list of dotted module names of IPython extensions to load. -# See also: InteractiveShellApp.extensions -# c.IPKernelApp.extensions = [] - -## Path to an extra config file to load. -# See also: BaseIPythonApplication.extra_config_file -# c.IPKernelApp.extra_config_file = '' - -## -# See also: InteractiveShellApp.extra_extensions -# c.IPKernelApp.extra_extensions = [] - -## A file to be run -# See also: InteractiveShellApp.file_to_run -# c.IPKernelApp.file_to_run = '' - -## Enable GUI event loop integration with any of ('asyncio', 'glut', 'gtk', -# 'gtk2', 'gtk3', 'gtk4', 'osx', 'pyglet', 'qt', 'qt5', 'qt6', 'tk', 'wx', -# 'gtk2', 'qt4'). -# See also: InteractiveShellApp.gui -# c.IPKernelApp.gui = None - -## set the heartbeat port [default: random] -# See also: ConnectionFileMixin.hb_port -# c.IPKernelApp.hb_port = 0 - -## Should variables loaded at startup (by startup files, exec_lines, etc.) -# See also: InteractiveShellApp.hide_initial_ns -# c.IPKernelApp.hide_initial_ns = True - -## If True, IPython will not add the current working directory to sys.path. -# See also: InteractiveShellApp.ignore_cwd -# c.IPKernelApp.ignore_cwd = False - -## ONLY USED ON WINDOWS -# Interrupt this process when the parent is signaled. -# Default: 0 -# c.IPKernelApp.interrupt = 0 - -## set the iopub (PUB) port [default: random] -# See also: ConnectionFileMixin.iopub_port -# c.IPKernelApp.iopub_port = 0 - -## Set the kernel's IP address [default localhost]. -# See also: ConnectionFileMixin.ip -# c.IPKernelApp.ip = '' - -## -# See also: BaseIPythonApplication.ipython_dir -# c.IPKernelApp.ipython_dir = '' - -## The Kernel subclass to be used. -# -# This should allow easy reuse of the IPKernelApp entry point -# to configure and launch kernels other than IPython's own. -# Default: 'ipykernel.ipkernel.IPythonKernel' -# c.IPKernelApp.kernel_class = 'ipykernel.ipkernel.IPythonKernel' - -## The date format used by logging formatters for %(asctime)s -# See also: Application.log_datefmt -# c.IPKernelApp.log_datefmt = '%Y-%m-%d %H:%M:%S' - -## The Logging format template -# See also: Application.log_format -# c.IPKernelApp.log_format = '[%(name)s]%(highlevel)s %(message)s' - -## Set the log level by value or name. -# See also: Application.log_level -# c.IPKernelApp.log_level = 30 - -## -# See also: Application.logging_config -# c.IPKernelApp.logging_config = {} - -## Configure matplotlib for interactive use with -# See also: InteractiveShellApp.matplotlib -# c.IPKernelApp.matplotlib = None - -## Run the module as a script. -# See also: InteractiveShellApp.module_to_run -# c.IPKernelApp.module_to_run = '' - -## redirect stderr to the null device -# Default: False -# c.IPKernelApp.no_stderr = False - -## redirect stdout to the null device -# Default: False -# c.IPKernelApp.no_stdout = False - -## The importstring for the OutStream factory -# Default: 'ipykernel.iostream.OutStream' -# c.IPKernelApp.outstream_class = 'ipykernel.iostream.OutStream' - -## Whether to overwrite existing config files when copying -# See also: BaseIPythonApplication.overwrite -# c.IPKernelApp.overwrite = False - -## kill this process if its parent dies. On Windows, the argument -# specifies the HANDLE of the parent process, otherwise it is simply boolean. -# Default: 0 -# c.IPKernelApp.parent_handle = 0 - -## The IPython profile to use. -# See also: BaseIPythonApplication.profile -# c.IPKernelApp.profile = 'default' - -## Pre-load matplotlib and numpy for interactive use, -# See also: InteractiveShellApp.pylab -# c.IPKernelApp.pylab = None - -## If true, IPython will populate the user namespace with numpy, pylab, etc. -# See also: InteractiveShellApp.pylab_import_all -# c.IPKernelApp.pylab_import_all = True - -## Only send stdout/stderr to output stream -# Default: True -# c.IPKernelApp.quiet = True - -## Reraise exceptions encountered loading IPython extensions? -# See also: InteractiveShellApp.reraise_ipython_extension_failures -# c.IPKernelApp.reraise_ipython_extension_failures = False - -## set the shell (ROUTER) port [default: random] -# See also: ConnectionFileMixin.shell_port -# c.IPKernelApp.shell_port = 0 - -## Instead of starting the Application, dump configuration to stdout -# See also: Application.show_config -# c.IPKernelApp.show_config = False - -## Instead of starting the Application, dump configuration to stdout (as JSON) -# See also: Application.show_config_json -# c.IPKernelApp.show_config_json = False - -## set the stdin (ROUTER) port [default: random] -# See also: ConnectionFileMixin.stdin_port -# c.IPKernelApp.stdin_port = 0 - -# See also: ConnectionFileMixin.transport -# c.IPKernelApp.transport = 'tcp' - -## Set main event loop. -# Default: False -# c.IPKernelApp.trio_loop = False - -## Create a massive crash report when IPython encounters what may be an -# See also: BaseIPythonApplication.verbose_crash -# c.IPKernelApp.verbose_crash = False - -# ------------------------------------------------------------------------------ -# Kernel(SingletonConfigurable) configuration -# ------------------------------------------------------------------------------ -## The base kernel class. - -## Whether to use appnope for compatibility with OS X App Nap. -# -# Only affects OS X >= 10.9. -# Default: True -# c.Kernel._darwin_app_nap = True - -# Default: 0.0005 -# c.Kernel._execute_sleep = 0.0005 - -# Default: 0.01 -# c.Kernel._poll_interval = 0.01 - -## Set to False if you want to debug python standard and dependent libraries. -# Default: True -# c.Kernel.debug_just_my_code = True - -## time (in seconds) to wait for messages to arrive -# when aborting queued requests after an error. -# -# Requests that arrive within this window after an error -# will be cancelled. -# -# Increase in the event of unusually slow network -# causing significant delays, -# which can manifest as e.g. "Run all" in a notebook -# aborting some, but not all, messages after an error. -# Default: 0.0 -# c.Kernel.stop_on_error_timeout = 0.0 - -# ------------------------------------------------------------------------------ -# IPythonKernel(Kernel) configuration -# ------------------------------------------------------------------------------ -## The IPython Kernel class. - -## Whether to use appnope for compatibility with OS X App Nap. -# See also: Kernel._darwin_app_nap -# c.IPythonKernel._darwin_app_nap = True - -# See also: Kernel._execute_sleep -# c.IPythonKernel._execute_sleep = 0.0005 - -# See also: Kernel._poll_interval -# c.IPythonKernel._poll_interval = 0.01 - -## Set to False if you want to debug python standard and dependent libraries. -# See also: Kernel.debug_just_my_code -# c.IPythonKernel.debug_just_my_code = True - -# Default: [{'text': 'Python Reference', 'url': 'https://docs.python.org/3.10'}, {'text': 'IPython Reference', 'url': 'https://ipython.org/documentation.html'}, {'text': 'NumPy Reference', 'url': 'https://docs.scipy.org/doc/numpy/reference/'}, {'text': 'SciPy Reference', 'url': 'https://docs.scipy.org/doc/scipy/reference/'}, {'text': 'Matplotlib Reference', 'url': 'https://matplotlib.org/contents.html'}, {'text': 'SymPy Reference', 'url': 'http://docs.sympy.org/latest/index.html'}, {'text': 'pandas Reference', 'url': 'https://pandas.pydata.org/pandas-docs/stable/'}] -# c.IPythonKernel.help_links = [{'text': 'Python Reference', 'url': 'https://docs.python.org/3.10'}, {'text': 'IPython Reference', 'url': 'https://ipython.org/documentation.html'}, {'text': 'NumPy Reference', 'url': 'https://docs.scipy.org/doc/numpy/reference/'}, {'text': 'SciPy Reference', 'url': 'https://docs.scipy.org/doc/scipy/reference/'}, {'text': 'Matplotlib Reference', 'url': 'https://matplotlib.org/contents.html'}, {'text': 'SymPy Reference', 'url': 'http://docs.sympy.org/latest/index.html'}, {'text': 'pandas Reference', 'url': 'https://pandas.pydata.org/pandas-docs/stable/'}] - -## time (in seconds) to wait for messages to arrive -# See also: Kernel.stop_on_error_timeout -# c.IPythonKernel.stop_on_error_timeout = 0.0 - -## Set this flag to False to deactivate the use of experimental IPython -# completion APIs. -# Default: True -# c.IPythonKernel.use_experimental_completions = True - -# ------------------------------------------------------------------------------ -# InteractiveShell(SingletonConfigurable) configuration -# ------------------------------------------------------------------------------ -## An enhanced, interactive shell for Python. - -## 'all', 'last', 'last_expr' or 'none', 'last_expr_or_assign' specifying which -# nodes should be run interactively (displaying output from expressions). -# Choices: any of ['all', 'last', 'last_expr', 'none', 'last_expr_or_assign'] -# Default: 'last_expr' -# c.InteractiveShell.ast_node_interactivity = 'last_expr' - -## A list of ast.NodeTransformer subclass instances, which will be applied to -# user input before code is run. -# Default: [] -# c.InteractiveShell.ast_transformers = [] - -## Automatically run await statement in the top level repl. -# Default: True -# c.InteractiveShell.autoawait = True - -## Make IPython automatically call any callable object even if you didn't type -# explicit parentheses. For example, 'str 43' becomes 'str(43)' automatically. -# The value can be '0' to disable the feature, '1' for 'smart' autocall, where -# it is not applied if there are no more arguments on the line, and '2' for -# 'full' autocall, where all callable objects are automatically called (even if -# no arguments are present). -# Choices: any of [0, 1, 2] -# Default: 0 -# c.InteractiveShell.autocall = 0 - -## Autoindent IPython code entered interactively. -# Default: True -# c.InteractiveShell.autoindent = True - -## Enable magic commands to be called without the leading %. -# Default: True -# c.InteractiveShell.automagic = True - -## The part of the banner to be printed before the profile -# Default: "Python 3.10.14 (main, Mar 25 2024, 21:45:25) [GCC 12.2.0]\nType 'copyright', 'credits' or 'license' for more information\nIPython 8.22.2 -- An enhanced Interactive Python. Type '?' for help.\n" -# c.InteractiveShell.banner1 = "Python 3.10.14 (main, Mar 25 2024, 21:45:25) [GCC 12.2.0]\nType 'copyright', 'credits' or 'license' for more information\nIPython 8.22.2 -- An enhanced Interactive Python. Type '?' for help.\n" - -## The part of the banner to be printed after the profile -# Default: '' -# c.InteractiveShell.banner2 = '' - -## Set the size of the output cache. The default is 1000, you can change it -# permanently in your config file. Setting it to 0 completely disables the -# caching system, and the minimum value accepted is 3 (if you provide a value -# less than 3, it is reset to 0 and a warning is issued). This limit is defined -# because otherwise you'll spend more time re-flushing a too small cache than -# working -# Default: 1000 -# c.InteractiveShell.cache_size = 1000 - -## Use colors for displaying information about objects. Because this information -# is passed through a pager (like 'less'), and some pagers get confused with -# color codes, this capability can be turned off. -# Default: True -# c.InteractiveShell.color_info = True -# Default: False -# c.InteractiveShell.debug = False - -## Don't call post-execute functions that have failed in the past. -# Default: False -# c.InteractiveShell.disable_failing_post_execute = False - -## If True, anything that would be passed to the pager -# will be displayed as regular output instead. -# Default: False -# c.InteractiveShell.display_page = False - -## (Provisional API) enables html representation in mime bundles sent to pagers. -# Default: False -# c.InteractiveShell.enable_html_pager = False - -## Total length of command history -# Default: 10000 -# c.InteractiveShell.history_length = 10000 - -## The number of saved history entries to be loaded into the history buffer at -# startup. -# Default: 1000 -# c.InteractiveShell.history_load_length = 1000 - -## Class to use to instantiate the shell inspector -# Default: 'IPython.core.oinspect.Inspector' -# c.InteractiveShell.inspector_class = 'IPython.core.oinspect.Inspector' - -# Default: '' -# c.InteractiveShell.ipython_dir = '' - -## Start logging to the given file in append mode. Use `logfile` to specify a log -# file to **overwrite** logs to. -# Default: '' -# c.InteractiveShell.logappend = '' - -## The name of the logfile to use. -# Default: '' -# c.InteractiveShell.logfile = '' - -## Start logging to the default log file in overwrite mode. Use `logappend` to -# specify a log file to **append** logs to. -# Default: False -# c.InteractiveShell.logstart = False - -## Select the loop runner that will be used to execute top-level asynchronous -# code -# Default: 'IPython.core.interactiveshell._asyncio_runner' -# c.InteractiveShell.loop_runner = 'IPython.core.interactiveshell._asyncio_runner' - -# Choices: any of [0, 1, 2] -# Default: 0 -# c.InteractiveShell.object_info_string_level = 0 - -## Automatically call the pdb debugger after every exception. -# Default: False -# c.InteractiveShell.pdb = False - -# Default: False -# c.InteractiveShell.quiet = False - -# Default: '\n' -# c.InteractiveShell.separate_in = '\n' - -# Default: '' -# c.InteractiveShell.separate_out = '' - -# Default: '' -# c.InteractiveShell.separate_out2 = '' - -## Show rewritten input, e.g. for autocall. -# Default: True -# c.InteractiveShell.show_rewritten_input = True - -## Enables rich html representation of docstrings. (This requires the docrepr -# module). -# Default: False -# c.InteractiveShell.sphinxify_docstring = False - -## Warn if running in a virtual environment with no IPython installed (so IPython -# from the global environment is used). -# Default: True -# c.InteractiveShell.warn_venv = True - -# Default: True -# c.InteractiveShell.wildcards_case_sensitive = True - -## Switch modes for the IPython exception handlers. -# Choices: any of ['Context', 'Plain', 'Verbose', 'Minimal'] (case-insensitive) -# Default: 'Context' -# c.InteractiveShell.xmode = 'Context' - -# ------------------------------------------------------------------------------ -# ZMQInteractiveShell(InteractiveShell) configuration -# ------------------------------------------------------------------------------ -## A subclass of InteractiveShell for ZMQ. - -## -# See also: InteractiveShell.ast_node_interactivity -# c.ZMQInteractiveShell.ast_node_interactivity = 'last_expr' - -## -# See also: InteractiveShell.ast_transformers -# c.ZMQInteractiveShell.ast_transformers = [] - -## -# See also: InteractiveShell.autoawait -# c.ZMQInteractiveShell.autoawait = True - -## -# See also: InteractiveShell.autocall -# c.ZMQInteractiveShell.autocall = 0 - -## -# See also: InteractiveShell.automagic -# c.ZMQInteractiveShell.automagic = True - -## The part of the banner to be printed before the profile -# See also: InteractiveShell.banner1 -# c.ZMQInteractiveShell.banner1 = "Python 3.10.14 (main, Mar 25 2024, 21:45:25) [GCC 12.2.0]\nType 'copyright', 'credits' or 'license' for more information\nIPython 8.22.2 -- An enhanced Interactive Python. Type '?' for help.\n" - -## The part of the banner to be printed after the profile -# See also: InteractiveShell.banner2 -# c.ZMQInteractiveShell.banner2 = '' - -## -# See also: InteractiveShell.cache_size -# c.ZMQInteractiveShell.cache_size = 1000 - -## -# See also: InteractiveShell.color_info -# c.ZMQInteractiveShell.color_info = True - -## Set the color scheme (NoColor, Neutral, Linux, or LightBG). -# See also: InteractiveShell.colors -# c.ZMQInteractiveShell.colors = 'Neutral' - -# See also: InteractiveShell.debug -# c.ZMQInteractiveShell.debug = False - -## Don't call post-execute functions that have failed in the past. -# See also: InteractiveShell.disable_failing_post_execute -# c.ZMQInteractiveShell.disable_failing_post_execute = False - -## If True, anything that would be passed to the pager -# See also: InteractiveShell.display_page -# c.ZMQInteractiveShell.display_page = False - -## -# See also: InteractiveShell.enable_html_pager -# c.ZMQInteractiveShell.enable_html_pager = False - -## Total length of command history -# See also: InteractiveShell.history_length -# c.ZMQInteractiveShell.history_length = 10000 - -## -# See also: InteractiveShell.history_load_length -# c.ZMQInteractiveShell.history_load_length = 1000 - -## Class to use to instantiate the shell inspector -# See also: InteractiveShell.inspector_class -# c.ZMQInteractiveShell.inspector_class = 'IPython.core.oinspect.Inspector' - -# See also: InteractiveShell.ipython_dir -# c.ZMQInteractiveShell.ipython_dir = '' - -## -# See also: InteractiveShell.logappend -# c.ZMQInteractiveShell.logappend = '' - -## -# See also: InteractiveShell.logfile -# c.ZMQInteractiveShell.logfile = '' - -## -# See also: InteractiveShell.logstart -# c.ZMQInteractiveShell.logstart = False - -## Select the loop runner that will be used to execute top-level asynchronous -# code -# See also: InteractiveShell.loop_runner -# c.ZMQInteractiveShell.loop_runner = 'IPython.core.interactiveshell._asyncio_runner' - -# See also: InteractiveShell.object_info_string_level -# c.ZMQInteractiveShell.object_info_string_level = 0 - -## -# See also: InteractiveShell.pdb -# c.ZMQInteractiveShell.pdb = False - -# See also: InteractiveShell.quiet -# c.ZMQInteractiveShell.quiet = False - -# See also: InteractiveShell.separate_in -# c.ZMQInteractiveShell.separate_in = '\n' - -# See also: InteractiveShell.separate_out -# c.ZMQInteractiveShell.separate_out = '' - -# See also: InteractiveShell.separate_out2 -# c.ZMQInteractiveShell.separate_out2 = '' - -## Show rewritten input, e.g. for autocall. -# See also: InteractiveShell.show_rewritten_input -# c.ZMQInteractiveShell.show_rewritten_input = True - -## -# See also: InteractiveShell.sphinxify_docstring -# c.ZMQInteractiveShell.sphinxify_docstring = False - -## Warn if running in a virtual environment with no IPython installed (so IPython -# from the global environment is used). -# See also: InteractiveShell.warn_venv -# c.ZMQInteractiveShell.warn_venv = True - -# See also: InteractiveShell.wildcards_case_sensitive -# c.ZMQInteractiveShell.wildcards_case_sensitive = True - -## Switch modes for the IPython exception handlers. -# See also: InteractiveShell.xmode -# c.ZMQInteractiveShell.xmode = 'Context' - -# ------------------------------------------------------------------------------ -# ProfileDir(LoggingConfigurable) configuration -# ------------------------------------------------------------------------------ -## An object to manage the profile directory and its resources. -# -# The profile directory is used by all IPython applications, to manage -# configuration, logging and security. -# -# This object knows how to find, create and manage these directories. This -# should be used by any code that wants to handle profiles. - -## Set the profile location directly. This overrides the logic used by the -# `profile` option. -# Default: '' -# c.ProfileDir.location = '' - -# ------------------------------------------------------------------------------ -# Session(Configurable) configuration -# ------------------------------------------------------------------------------ -## Object for handling serialization and sending of messages. -# -# The Session object handles building messages and sending them -# with ZMQ sockets or ZMQStream objects. Objects can communicate with each -# other over the network via Session objects, and only need to work with the -# dict-based IPython message spec. The Session will handle -# serialization/deserialization, security, and metadata. -# -# Sessions support configurable serialization via packer/unpacker traits, -# and signing with HMAC digests via the key/keyfile traits. -# -# Parameters -# ---------- -# -# debug : bool -# whether to trigger extra debugging statements -# packer/unpacker : str : 'json', 'pickle' or import_string -# importstrings for methods to serialize message parts. If just -# 'json' or 'pickle', predefined JSON and pickle packers will be used. -# Otherwise, the entire importstring must be used. -# -# The functions must accept at least valid JSON input, and output -# *bytes*. -# -# For example, to use msgpack: -# packer = 'msgpack.packb', unpacker='msgpack.unpackb' -# pack/unpack : callables -# You can also set the pack/unpack callables for serialization directly. -# session : bytes -# the ID of this Session object. The default is to generate a new UUID. -# username : unicode -# username added to message headers. The default is to ask the OS. -# key : bytes -# The key used to initialize an HMAC signature. If unset, messages -# will not be signed or checked. -# keyfile : filepath -# The file containing a key. If this is set, `key` will be initialized -# to the contents of the file. - -## Threshold (in bytes) beyond which an object's buffer should be extracted to -# avoid pickling. -# Default: 1024 -# c.Session.buffer_threshold = 1024 - -## Whether to check PID to protect against calls after fork. -# -# This check can be disabled if fork-safety is handled elsewhere. -# Default: True -# c.Session.check_pid = True - -## Threshold (in bytes) beyond which a buffer should be sent without copying. -# Default: 65536 -# c.Session.copy_threshold = 65536 - -## Debug output in the Session -# Default: False -# c.Session.debug = False - -## The maximum number of digests to remember. -# -# The digest history will be culled when it exceeds this value. -# Default: 65536 -# c.Session.digest_history_size = 65536 - -## The maximum number of items for a container to be introspected for custom serialization. -# Containers larger than this are pickled outright. -# Default: 64 -# c.Session.item_threshold = 64 - -## execution key, for signing messages. -# Default: b'' -# c.Session.key = b'' - -## path to file containing execution key. -# Default: '' -# c.Session.keyfile = '' - -## Metadata dictionary, which serves as the default top-level metadata dict for -# each message. -# Default: {} -# c.Session.metadata = {} - -## The name of the packer for serializing messages. -# Should be one of 'json', 'pickle', or an import name -# for a custom callable serializer. -# Default: 'json' -# c.Session.packer = 'json' - -## The UUID identifying this session. -# Default: '' -# c.Session.session = '' - -## The digest scheme used to construct the message signatures. -# Must have the form 'hmac-HASH'. -# Default: 'hmac-sha256' -# c.Session.signature_scheme = 'hmac-sha256' - -## The name of the unpacker for unserializing messages. -# Only used with custom functions for `packer`. -# Default: 'json' -# c.Session.unpacker = 'json' - -## Username for the Session. Default is your system username. -# Default: 'user' -# c.Session.username = 'user' - -# Truncate large collections (lists, dicts, tuples, sets) to this size. -# Set to 0 to disable truncation. -# Default: 1000 -c.PlainTextFormatter.max_seq_length = 0 diff --git a/template/jupyter-healthcheck.sh b/template/jupyter-healthcheck.sh deleted file mode 100644 index e604a06c..00000000 --- a/template/jupyter-healthcheck.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# Custom health check for Jupyter Server -# Verifies the server is responsive via the /api/status endpoint - -MAX_RETRIES=50 -RETRY_INTERVAL=0.2 - -for i in $(seq 1 $MAX_RETRIES); do - status_code=$(curl --unix-socket /run/e2b-jupyter/server.sock -s -o /dev/null -w "%{http_code}" "http://localhost/api/status") - - if [ "$status_code" -eq 200 ]; then - echo "Jupyter Server is healthy" - exit 0 - fi - - if [ $((i % 10)) -eq 0 ]; then - echo "Waiting for Jupyter Server to become healthy... (attempt $i/$MAX_RETRIES)" - fi - sleep $RETRY_INTERVAL -done - -echo "Jupyter Server health check failed after $MAX_RETRIES attempts" -exit 1 diff --git a/template/jupyter_server_config.py b/template/jupyter_server_config.py deleted file mode 100644 index 4d6985dc..00000000 --- a/template/jupyter_server_config.py +++ /dev/null @@ -1,67 +0,0 @@ -# Configuration file for jupyter-server. - -c = get_config() # noqa - -c.ServerApp.sock = "/run/e2b-jupyter/server.sock" -c.ServerApp.sock_mode = "0600" - - -# Pin the contents root directory. -# -# Sessions are created with a relative path (a bare uuid, see -# server/contexts.py). Without an explicit root_dir, jupyter-server -# inherits the process working directory as its root — which is "/" -# under systemd (jupyter.service has no WorkingDirectory). Since -# jupyter-server 2.18.0 (CVE-2026-35397 path-traversal hardening), a -# root_dir of "/" makes every POST /api/sessions fail with -# " is outside root contents directory", so the server never -# starts. Pinning it to /home/user matches the execution cwd. -c.ServerApp.root_dir = "/home/user" - - -# Set the Access-Control-Allow-Origin header -# -# Use '*' to allow any origin to access your server. -# -# Takes precedence over allow_origin_pat. -# Default: '' -c.ServerApp.allow_origin = "" - - -# Allow requests where the Host header doesn't point to a local server -# -# By default, requests get a 403 forbidden response if the 'Host' header -# shows that the browser thinks it's on a non-local domain. -# Setting this option to True disables this check. -# -# This protects against 'DNS rebinding' attacks, where a remote web server -# serves you a page and then changes its DNS to send later requests to a -# local IP, bypassing same-origin checks. -# -# Local IP addresses (such as 127.0.0.1 and ::1) are allowed as local, -# along with hostnames configured in local_hostnames. -# Default: False -c.ServerApp.allow_remote_access = False - -# Disable cross-site-request-forgery protection -# -# Jupyter server includes protection from cross-site request forgeries, -# requiring API requests to either: -# -# - originate from pages served by this server (validated with XSRF cookie and token), or -# - authenticate with a token -# -# Some anonymous compute resources still desire the ability to run code, -# completely without authentication. -# These services can disable all authentication and security checks, -# with the full knowledge of what that implies. -# Default: False -c.ServerApp.disable_check_xsrf = True - -# Whether to allow the user to run the server as root. -# Default: False -c.ServerApp.allow_root = True - -# (bytes/sec) Maximum rate at which messages can be sent on iopub before they are limited. -# Default: 1000000 -c.ServerApp.iopub_data_rate_limit = 1000000000 diff --git a/template/matplotlibrc b/template/matplotlibrc deleted file mode 100644 index b71d01f3..00000000 --- a/template/matplotlibrc +++ /dev/null @@ -1 +0,0 @@ -font.family: sans-serif, Noto Sans CJK JP diff --git a/template/package.json b/template/package.json deleted file mode 100644 index 5fc2b13a..00000000 --- a/template/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "@e2b/code-interpreter-template", - "private": true, - "version": "0.4.6", - "scripts": { - "lint": "ruff check .", - "format": "ruff format ." - } -} diff --git a/template/requirements-dev.txt b/template/requirements-dev.txt deleted file mode 100644 index fa0feda2..00000000 --- a/template/requirements-dev.txt +++ /dev/null @@ -1,2 +0,0 @@ -e2b==2.32.0 -python-dotenv==1.2.2 \ No newline at end of file diff --git a/template/requirements.txt b/template/requirements.txt deleted file mode 100644 index 3e453aa1..00000000 --- a/template/requirements.txt +++ /dev/null @@ -1,44 +0,0 @@ -# Jupyter server requirements -jupyter-server==2.20.0 -ipykernel==6.31.0 -ipython==9.15.0 - -orjson==3.11.9 -pandas==2.2.3 -matplotlib==3.10.9 -pillow==12.3.0 - -# Latest version for -e2b_charts - -# Other packages -aiohttp==3.14.3 -beautifulsoup4==4.15.0 -bokeh==3.9.1 -gensim==4.4.0 -imageio==2.37.3 -joblib==1.5.3 -librosa==0.11.0 -nltk==3.10.3 -numpy==2.3.5 -numba==0.66.0 -opencv-python==4.11.0.86 -openpyxl==3.1.5 -plotly==6.0.1 -kaleido==1.3.0 -pytest==9.0.3 -python-docx==1.1.2 -pytz==2025.2 -requests==2.33.0 -scikit-image==0.25.2 -scikit-learn==1.6.1 -scipy==1.17.1 -seaborn==0.13.2 -soundfile==0.13.1 -spacy==3.8.14 -textblob==0.19.0 -tornado==6.5.8 -urllib3==2.7.0 -xarray==2025.4.0 -xlrd==2.0.2 -sympy==1.14.0 diff --git a/template/server/api/models/__init__.py b/template/server/api/models/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/template/server/api/models/context.py b/template/server/api/models/context.py deleted file mode 100644 index 5efb850e..00000000 --- a/template/server/api/models/context.py +++ /dev/null @@ -1,11 +0,0 @@ -from pydantic import BaseModel, StrictStr -from pydantic import Field - - -class Context(BaseModel): - id: StrictStr = Field(description="Context ID") - language: StrictStr = Field(description="Language of the context") - cwd: StrictStr = Field(description="Current working directory of the context") - - def __hash__(self): - return hash(self.id) diff --git a/template/server/api/models/create_context.py b/template/server/api/models/create_context.py deleted file mode 100644 index 1e1fefb7..00000000 --- a/template/server/api/models/create_context.py +++ /dev/null @@ -1,13 +0,0 @@ -from pydantic import BaseModel, StrictStr -from pydantic import Field -from typing import Optional - - -class CreateContext(BaseModel): - cwd: Optional[StrictStr] = Field( - default="/home/user", - description="Current working directory", - ) - language: Optional[StrictStr] = Field( - default="python", description="Language of the context" - ) diff --git a/template/server/api/models/env_vars.py b/template/server/api/models/env_vars.py deleted file mode 100644 index 7c51bcca..00000000 --- a/template/server/api/models/env_vars.py +++ /dev/null @@ -1,4 +0,0 @@ -from typing import Dict -from pydantic import StrictStr - -EnvVars = Dict[StrictStr, str] diff --git a/template/server/api/models/error.py b/template/server/api/models/error.py deleted file mode 100644 index b17a6abc..00000000 --- a/template/server/api/models/error.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field - -from api.models.output import OutputType - - -class Error(BaseModel): - type: OutputType = OutputType.ERROR - - name: Optional[StrictStr] = Field(default=None, description="Name of the exception") - value: Optional[StrictStr] = Field( - default=None, description="Value of the exception" - ) - traceback: Optional[StrictStr] = Field( - default=None, description="Traceback of the exception" - ) diff --git a/template/server/api/models/execution_request.py b/template/server/api/models/execution_request.py deleted file mode 100644 index bb691e9e..00000000 --- a/template/server/api/models/execution_request.py +++ /dev/null @@ -1,16 +0,0 @@ -from typing import Optional -from pydantic import BaseModel, StrictStr -from pydantic import Field - -from .env_vars import EnvVars - - -class ExecutionRequest(BaseModel): - code: StrictStr = Field(description="Code to be executed") - context_id: Optional[StrictStr] = Field(default=None, description="Context ID") - language: Optional[StrictStr] = Field( - default=None, description="Language of the code" - ) - env_vars: Optional[EnvVars] = Field( - description="Environment variables", default=None - ) diff --git a/template/server/api/models/logs.py b/template/server/api/models/logs.py deleted file mode 100644 index d9a433fe..00000000 --- a/template/server/api/models/logs.py +++ /dev/null @@ -1,19 +0,0 @@ -import datetime - - -from typing import Optional -from pydantic import BaseModel, StrictStr - -from api.models.output import OutputType - - -class Stdout(BaseModel): - type: OutputType = OutputType.STDOUT - text: Optional[StrictStr] = None - timestamp: Optional[datetime.datetime] = None - - -class Stderr(BaseModel): - type: OutputType = OutputType.STDERR - text: Optional[StrictStr] = None - timestamp: Optional[datetime.datetime] = None diff --git a/template/server/api/models/output.py b/template/server/api/models/output.py deleted file mode 100644 index 8e620c38..00000000 --- a/template/server/api/models/output.py +++ /dev/null @@ -1,31 +0,0 @@ -from __future__ import annotations - -from enum import Enum -from pydantic import BaseModel - - -class OutputType(Enum): - """ - Represents the type of the data to send to the client. - """ - - STDOUT = "stdout" - STDERR = "stderr" - RESULT = "result" - ERROR = "error" - NUMBER_OF_EXECUTIONS = "number_of_executions" - END_OF_EXECUTION = "end_of_execution" - UNEXPECTED_END_OF_EXECUTION = "unexpected_end_of_execution" - - -class EndOfExecution(BaseModel): - type: OutputType = OutputType.END_OF_EXECUTION - - -class UnexpectedEndOfExecution(BaseModel): - type: OutputType = OutputType.UNEXPECTED_END_OF_EXECUTION - - -class NumberOfExecutions(BaseModel): - type: OutputType = OutputType.NUMBER_OF_EXECUTIONS - execution_count: int diff --git a/template/server/api/models/result.py b/template/server/api/models/result.py deleted file mode 100644 index 90e24a9a..00000000 --- a/template/server/api/models/result.py +++ /dev/null @@ -1,105 +0,0 @@ -from __future__ import annotations - -import warnings - -from typing import Optional, Iterable -from pydantic import BaseModel - -from api.models.output import OutputType - -warnings.filterwarnings("ignore", category=UserWarning) - - -class Result(BaseModel): - """ - Represents the data to be displayed as a result of executing a cell in a Jupyter notebook. - The result is similar to the structure returned by ipython kernel: https://ipython.readthedocs.io/en/stable/development/execution.html#execution-semantics - - The result can contain multiple types of data, such as text, images, plots, etc. Each type of data is represented - as a string, and the result can contain multiple types of data. The display calls don't have to have text representation, - for the actual result the representation is always present for the result, the other representations are always optional. - """ - - type: OutputType = OutputType.RESULT - - text: Optional[str] = None - html: Optional[str] = None - markdown: Optional[str] = None - svg: Optional[str] = None - png: Optional[str] = None - jpeg: Optional[str] = None - pdf: Optional[str] = None - latex: Optional[str] = None - json: Optional[dict] = None - javascript: Optional[str] = None - data: Optional[dict] = None - chart: Optional[dict] = None - extra: Optional[dict] = None - "Extra data that can be included. Not part of the standard types." - - is_main_result: Optional[bool] = None - "Whether this data is the result of the execetution. Data can be produced by display calls of which can be multiple in a cell." - - def __init__(self, is_main_result: bool, data: [str, str]): - super().__init__() - self.is_main_result = is_main_result - - self.text = data.pop("text/plain", None) - if self.text and ( - (self.text.startswith("'") and self.text.endswith("'")) - or (self.text.startswith('"') and self.text.endswith('"')) - ): - self.text = self.text[1:-1] - - self.html = data.pop("text/html", None) - self.markdown = data.pop("text/markdown", None) - self.svg = data.pop("image/svg+xml", None) - self.png = data.pop("image/png", None) - self.jpeg = data.pop("image/jpeg", None) - self.pdf = data.pop("application/pdf", None) - self.latex = data.pop("text/latex", None) - self.json = data.pop("application/json", None) - self.javascript = data.pop("application/javascript", None) - self.data = data.pop("e2b/data", None) - self.chart = data.pop("e2b/chart", None) - self.extra = data - - def formats(self) -> Iterable[str]: - formats = [] - - for key in [ - "text", - "html", - "markdown", - "svg", - "png", - "jpeg", - "pdf", - "latex", - "json", - "javascript", - "data", - "chart", - ]: - if getattr(self, key): - formats.append(key) - - if self.extra: - for key in self.extra: - formats.append(key) - - return formats - - def __str__(self) -> str: - """ - Returns the text representation of the data. - - :return: The text representation of the data. - """ - return self.__repr__() - - def __repr__(self) -> str: - if self.text: - return f"Result({self.text})" - formats = self.formats() - return f"Result with formats: {formats}" diff --git a/template/server/consts.py b/template/server/consts.py deleted file mode 100644 index c861dc78..00000000 --- a/template/server/consts.py +++ /dev/null @@ -1,2 +0,0 @@ -JUPYTER_SOCKET_PATH = "/run/e2b-jupyter/server.sock" -JUPYTER_BASE_URL = "http://localhost" diff --git a/template/server/contexts.py b/template/server/contexts.py deleted file mode 100644 index 773f3fa8..00000000 --- a/template/server/contexts.py +++ /dev/null @@ -1,72 +0,0 @@ -import logging -import uuid -from typing import Optional - -from api.models.context import Context -from fastapi.responses import PlainTextResponse - -from consts import JUPYTER_BASE_URL -from errors import ExecutionError -from messaging import ContextWebSocket - -logger = logging.Logger(__name__) - - -def get_kernel_for_language(language: str) -> str: - if language == "typescript": - return "javascript" - - return language - - -def normalize_language(language: Optional[str]) -> str: - if not language: - return "python" - - language = language.lower().strip() - - if language == "js": - return "javascript" - - if language == "ts": - return "typescript" - - return language - - -async def create_context(client, websockets: dict, language: str, cwd: str) -> Context: - data = { - "path": str(uuid.uuid4()), - "kernel": {"name": get_kernel_for_language(language)}, - "type": "notebook", - "name": str(uuid.uuid4()), - } - logger.debug(f"Creating new {language} context") - - response = await client.post(f"{JUPYTER_BASE_URL}/api/sessions", json=data) - - if not response.is_success: - raise Exception( - f"Failed to create context: {response.text}", - ) - - session_data = response.json() - session_id = session_data["id"] - context_id = session_data["kernel"]["id"] - - logger.debug(f"Created context {context_id}") - - ws = ContextWebSocket(context_id, session_id, language, cwd) - await ws.connect() - websockets[context_id] = ws - - logger.info(f"Setting working directory to {cwd}") - try: - await ws.change_current_directory(cwd, language) - except ExecutionError: - return PlainTextResponse( - "Failed to set working directory", - status_code=500, - ) - - return Context(language=language, id=context_id, cwd=cwd) diff --git a/template/server/envs.py b/template/server/envs.py deleted file mode 100644 index 8752e7b9..00000000 --- a/template/server/envs.py +++ /dev/null @@ -1,20 +0,0 @@ -import os -from typing import Optional - -import httpx - -LOCAL = os.getenv("E2B_LOCAL", False) -ENVD_PORT = 49983 - - -async def get_envs(access_token: Optional[str]) -> dict: - if LOCAL: - return {"E2B_TEST_VARIABLE": "true"} - async with httpx.AsyncClient() as client: - headers = {} - if access_token: - headers["X-Access-Token"] = f"{access_token}" - response = await client.get( - f"http://localhost:{ENVD_PORT}/envs", headers=headers - ) - return response.json() diff --git a/template/server/errors.py b/template/server/errors.py deleted file mode 100644 index ab4b43bc..00000000 --- a/template/server/errors.py +++ /dev/null @@ -1,2 +0,0 @@ -class ExecutionError(Exception): - pass diff --git a/template/server/main.py b/template/server/main.py deleted file mode 100644 index a8d43b74..00000000 --- a/template/server/main.py +++ /dev/null @@ -1,219 +0,0 @@ -import logging -import sys -import httpx - -from typing import Dict, Union, Literal, List - -from contextlib import asynccontextmanager -from fastapi import FastAPI, Request -from fastapi.middleware.cors import CORSMiddleware -from fastapi.responses import PlainTextResponse - -from api.models.context import Context -from api.models.create_context import CreateContext -from api.models.execution_request import ExecutionRequest -from consts import JUPYTER_BASE_URL, JUPYTER_SOCKET_PATH -from contexts import create_context, normalize_language -from messaging import ContextWebSocket -from stream import StreamingListJsonResponse -from utils.locks import LockedMap - -logging.basicConfig(level=logging.DEBUG, stream=sys.stdout) -logger = logging.Logger(__name__) -http_logger = logging.getLogger("httpcore.http11") -http_logger.setLevel(logging.WARNING) - - -websockets: Dict[Union[str, Literal["default"]], ContextWebSocket] = {} -default_websockets = LockedMap() -global client - - -@asynccontextmanager -async def lifespan(app: FastAPI): - global client - client = httpx.AsyncClient( - transport=httpx.AsyncHTTPTransport(uds=JUPYTER_SOCKET_PATH), trust_env=False - ) - - try: - python_context = await create_context( - client, websockets, "python", "/home/user" - ) - default_websockets["python"] = python_context.id - websockets["default"] = websockets[python_context.id] - - javascript_context = await create_context( - client, websockets, "javascript", "/home/user" - ) - default_websockets["javascript"] = javascript_context.id - - logger.info("Connected to default runtime") - yield - - # Will cleanup after application shuts down - for ws in websockets.values(): - await ws.close() - - await client.aclose() - except Exception as e: - logger.error(f"Failed to initialize default context: {e}") - raise - - -app = FastAPI(lifespan=lifespan) - -app.add_middleware( - CORSMiddleware, - allow_origins=["*"], - allow_methods=["*"], - allow_headers=["*"], -) - -logger.info("Starting Code Interpreter server") - - -@app.get("/health") -async def get_health(): - return "OK" - - -@app.post("/execute") -async def post_execute(request: Request, exec_request: ExecutionRequest): - logger.info(f"Executing code: {exec_request.code}") - - if exec_request.context_id and exec_request.language: - return PlainTextResponse( - "Only one of context_id or language can be provided", - status_code=400, - ) - - context_id = None - if exec_request.language: - language = normalize_language(exec_request.language) - - async with await default_websockets.get_lock(language): - context_id = default_websockets.get(language) - - if not context_id: - try: - context = await create_context( - client, websockets, language, "/home/user" - ) - except Exception as e: - return PlainTextResponse(str(e), status_code=500) - - context_id = context.id - default_websockets[language] = context_id - - elif exec_request.context_id: - context_id = exec_request.context_id - - if context_id: - ws = websockets.get(context_id, None) - else: - ws = websockets["default"] - - if not ws: - return PlainTextResponse( - f"Context {exec_request.context_id} not found", - status_code=404, - ) - - return StreamingListJsonResponse( - ws.execute( - exec_request.code, - env_vars=exec_request.env_vars, - access_token=request.headers.get("X-Access-Token", None), - ) - ) - - -@app.post("/contexts") -async def post_contexts(request: CreateContext) -> Context: - logger.info("Creating a new context") - - language = normalize_language(request.language) - cwd = request.cwd or "/home/user" - - try: - return await create_context(client, websockets, language, cwd) - except Exception as e: - return PlainTextResponse(str(e), status_code=500) - - -@app.get("/contexts") -async def get_contexts() -> List[Context]: - logger.info("Listing contexts") - - return [ - Context( - id=ws.context_id, - language=ws.language, - cwd=ws.cwd, - ) - for key, ws in websockets.items() - if key != "default" - ] - - -@app.post("/contexts/{context_id}/restart") -async def restart_context(context_id: str) -> None: - logger.info(f"Restarting context {context_id}") - - ws = websockets.get(context_id, None) - if not ws: - return PlainTextResponse( - f"Context {context_id} not found", - status_code=404, - ) - - session_id = ws.session_id - - await ws.close() - - response = await client.post( - f"{JUPYTER_BASE_URL}/api/kernels/{ws.context_id}/restart" - ) - if not response.is_success: - return PlainTextResponse( - f"Failed to restart context {context_id}", - status_code=500, - ) - - ws = ContextWebSocket( - ws.context_id, - session_id, - ws.language, - ws.cwd, - ) - - await ws.connect() - - websockets[context_id] = ws - - -@app.delete("/contexts/{context_id}") -async def remove_context(context_id: str) -> None: - logger.info(f"Removing context {context_id}") - - ws = websockets.get(context_id, None) - if not ws: - return PlainTextResponse( - f"Context {context_id} not found", - status_code=404, - ) - - try: - await ws.close() - except: # noqa: E722 - pass - - response = await client.delete(f"{JUPYTER_BASE_URL}/api/kernels/{ws.context_id}") - if not response.is_success: - return PlainTextResponse( - f"Failed to remove context {context_id}", - status_code=500, - ) - - del websockets[context_id] diff --git a/template/server/messaging.py b/template/server/messaging.py deleted file mode 100644 index 7248a5b4..00000000 --- a/template/server/messaging.py +++ /dev/null @@ -1,612 +0,0 @@ -import datetime -import json -import logging -import uuid -import asyncio - -import httpx - -from asyncio import Queue -from typing import ( - Dict, - Optional, - Union, -) -from pydantic import StrictStr -from websockets.client import WebSocketClientProtocol, unix_connect -from websockets.exceptions import ( - ConnectionClosedError, - WebSocketException, -) - -from api.models.error import Error -from api.models.logs import Stdout, Stderr -from api.models.result import Result -from api.models.output import ( - EndOfExecution, - NumberOfExecutions, - OutputType, - UnexpectedEndOfExecution, -) -from consts import JUPYTER_BASE_URL, JUPYTER_SOCKET_PATH -from errors import ExecutionError -from envs import get_envs - -logger = logging.getLogger(__name__) - -MAX_RECONNECT_RETRIES = 3 -PING_TIMEOUT = 30 -KEEPALIVE_INTERVAL = 5 # seconds between keepalive pings during streaming - - -class Execution: - def __init__(self, in_background: bool = False): - self.queue = Queue[ - Union[ - Result, - Error, - Stdout, - Stderr, - EndOfExecution, - NumberOfExecutions, - UnexpectedEndOfExecution, - ] - ]() - self.input_accepted = False - self.errored = False - self.in_background = in_background - - -class ContextWebSocket: - _ws: Optional[WebSocketClientProtocol] = None - _receive_task: Optional[asyncio.Task] = None - _global_env_vars: Optional[Dict[StrictStr, str]] = None - _cleanup_task: Optional[asyncio.Task] = None - - def __init__(self, context_id: str, session_id: str, language: str, cwd: str): - self.language = language - self.cwd = cwd - self.context_id = context_id - self.url = f"ws://localhost/api/kernels/{context_id}/channels" - self.session_id = session_id - self._executions: Dict[str, Execution] = {} - self._lock = asyncio.Lock() - - async def reconnect(self): - if self._ws is not None: - await self._ws.close(reason="Reconnecting") - - if self._receive_task is not None: - await self._receive_task - - await self.connect() - - async def connect(self): - logger.debug(f"WebSocket connecting to {self.url}") - - ws_logger = logger.getChild("websockets.client") - ws_logger.setLevel(logging.ERROR) - - self._ws = await unix_connect( - JUPYTER_SOCKET_PATH, - uri=self.url, - ping_timeout=PING_TIMEOUT, - max_size=None, - max_queue=None, - logger=ws_logger, - ) - - logger.info(f"WebSocket connected to {self.url}") - self._receive_task = asyncio.create_task( - self._receive_message(), - name="receive_message", - ) - - async def interrupt(self): - """Interrupt the current kernel execution via the Jupyter REST API.""" - try: - async with httpx.AsyncClient( - transport=httpx.AsyncHTTPTransport(uds=JUPYTER_SOCKET_PATH), - trust_env=False, - ) as client: - response = await client.post( - f"{JUPYTER_BASE_URL}/api/kernels/{self.context_id}/interrupt" - ) - if response.is_success: - logger.info(f"Kernel {self.context_id} interrupted successfully") - else: - logger.error( - f"Failed to interrupt kernel {self.context_id}: {response.status_code}" - ) - except Exception as e: - logger.error(f"Error interrupting kernel {self.context_id}: {e}") - - def _get_execute_request( - self, msg_id: str, code: Union[str, StrictStr], background: bool - ) -> str: - return json.dumps( - { - "header": { - "msg_id": msg_id, - "username": "e2b", - "session": self.session_id, - "msg_type": "execute_request", - "version": "5.3", - "date": datetime.datetime.now(datetime.timezone.utc).isoformat(), - }, - "parent_header": {}, - "metadata": { - "trusted": True, - "deletedCells": [], - "recordTiming": False, - "cellId": str(uuid.uuid4()), - }, - "content": { - "code": code, - "silent": background, - "store_history": True, - "user_expressions": {}, - "stop_on_error": True, - "allow_stdin": False, - }, - } - ) - - def _set_env_var_snippet(self, key: str, value: str) -> str: - """Get environment variable set command for the current language.""" - if self.language == "python": - return f"import os; os.environ['{key}'] = '{value}'" - elif self.language in ["javascript", "typescript"]: - return f"process.env['{key}'] = '{value}'" - elif self.language == "r": - return f'Sys.setenv({key} = "{value}")' - elif self.language == "java": - return f'System.setProperty("{key}", "{value}");' - elif self.language == "bash": - return f"export {key}='{value}'" - return "" - - def _delete_env_var_snippet(self, key: str) -> str: - """Get environment variable delete command for the current language.""" - if self.language == "python": - return f"import os; del os.environ['{key}']" - elif self.language in ["javascript", "typescript"]: - return f"delete process.env['{key}']" - elif self.language == "r": - return f"Sys.unsetenv('{key}')" - elif self.language == "java": - return f'System.clearProperty("{key}");' - elif self.language == "bash": - return f"unset {key}" - return "" - - def _set_env_vars_code(self, env_vars: Dict[StrictStr, str]) -> str: - """Build environment variable code for the current language.""" - env_commands = [] - for k, v in env_vars.items(): - command = self._set_env_var_snippet(k, v) - if command: - env_commands.append(command) - - return "\n".join(env_commands) - - def _reset_env_vars_code(self, env_vars: Dict[StrictStr, str]) -> str: - """Build environment variable cleanup code for the current language.""" - cleanup_commands = [] - - for key in env_vars: - # Check if this var exists in global env vars - if self._global_env_vars and key in self._global_env_vars: - # Reset to global value - value = self._global_env_vars[key] - command = self._set_env_var_snippet(key, value) - else: - # Remove the variable - command = self._delete_env_var_snippet(key) - - if command: - cleanup_commands.append(command) - - return "\n".join(cleanup_commands) - - def _get_code_indentation(self, code: str) -> str: - """Get the indentation from the first non-empty line of code.""" - if not code or not code.strip(): - return "" - - lines = code.split("\n") - for line in lines: - if line.strip(): # First non-empty line - return line[: len(line) - len(line.lstrip())] - - return "" - - def _indent_code_with_level(self, code: str, indent_level: str) -> str: - """Apply the given indentation level to each line of code.""" - if not code or not indent_level: - return code - - lines = code.split("\n") - indented_lines = [] - - for line in lines: - if line.strip(): # Non-empty lines - indented_lines.append(indent_level + line) - else: - indented_lines.append(line) - - return "\n".join(indented_lines) - - async def _cleanup_env_vars(self, env_vars: Dict[StrictStr, str]): - """Clean up environment variables in a separate execution request.""" - message_id = str(uuid.uuid4()) - self._executions[message_id] = Execution(in_background=True) - - try: - cleanup_code = self._reset_env_vars_code(env_vars) - if cleanup_code: - logger.info(f"Cleaning up env vars: {cleanup_code}") - request = self._get_execute_request(message_id, cleanup_code, True) - await self._ws.send(request) - - async for item in self._wait_for_result(message_id): - if item["type"] == "error": - logger.error(f"Error during env var cleanup: {item}") - finally: - del self._executions[message_id] - - async def _wait_for_result(self, message_id: str): - queue = self._executions[message_id].queue - - # Use a timeout on queue.get() to periodically send keepalives. - # Without keepalives, the generator blocks indefinitely waiting for - # kernel output. If the client silently disappears (e.g. network - # failure), uvicorn can only detect the broken connection when it - # tries to write — so we force a write every KEEPALIVE_INTERVAL - # seconds. This ensures timely disconnect detection and kernel - # interrupt for abandoned executions (see #213). - while True: - try: - output = await asyncio.wait_for(queue.get(), timeout=KEEPALIVE_INTERVAL) - except asyncio.TimeoutError: - # Yield a keepalive so Starlette writes to the socket. - # If the client has disconnected, the write fails and - # uvicorn delivers http.disconnect, which cancels this - # generator via CancelledError. - yield {"type": "keepalive"} - continue - - if output.type == OutputType.END_OF_EXECUTION: - break - - if output.type == OutputType.UNEXPECTED_END_OF_EXECUTION: - logger.error(f"Unexpected end of execution for code ({message_id})") - yield Error( - name="UnexpectedEndOfExecution", - value="Connection to the execution was closed before the execution was finished", - traceback="", - ) - break - - yield output.model_dump(exclude_none=True) - - async def change_current_directory( - self, path: Union[str, StrictStr], language: str - ): - message_id = str(uuid.uuid4()) - self._executions[message_id] = Execution(in_background=True) - if language == "python": - request = self._get_execute_request(message_id, f"%cd {path}", True) - elif language in ("javascript", "typescript"): - request = self._get_execute_request( - message_id, f"process.chdir('{path}')", True - ) - elif language == "r": - request = self._get_execute_request(message_id, f"setwd('{path}')", True) - # This does not actually change the working directory, but sets the user.dir property - elif language == "java": - request = self._get_execute_request( - message_id, f'System.setProperty("user.dir", "{path}");', True - ) - elif language == "bash": - request = self._get_execute_request(message_id, f"cd '{path}'", True) - else: - return - - await self._ws.send(request) - - async for item in self._wait_for_result(message_id): - if item["type"] == "error": - raise ExecutionError(f"Error during execution: {item}") - - async def execute( - self, - code: Union[str, StrictStr], - env_vars: Dict[StrictStr, str], - access_token: str, - ): - if self._ws is None: - raise Exception("WebSocket not connected") - - async with self._lock: - # Wait for any pending cleanup task to complete - if self._cleanup_task and not self._cleanup_task.done(): - logger.debug("Waiting for pending cleanup task to complete") - try: - await self._cleanup_task - except Exception as e: - logger.warning(f"Cleanup task failed: {e}") - finally: - self._cleanup_task = None - - # Get the indentation level from the code - code_indent = self._get_code_indentation(code) - - # Build the complete code snippet with env vars - complete_code = code - - global_env_vars_snippet = "" - env_vars_snippet = "" - - if self._global_env_vars is None: - self._global_env_vars = await get_envs(access_token=access_token) - global_env_vars_snippet = self._set_env_vars_code(self._global_env_vars) - - if env_vars: - env_vars_snippet = self._set_env_vars_code(env_vars) - - if global_env_vars_snippet or env_vars_snippet: - indented_env_code = self._indent_code_with_level( - f"{global_env_vars_snippet}\n{env_vars_snippet}", code_indent - ) - complete_code = f"{indented_env_code}\n{complete_code}" - - message_id = str(uuid.uuid4()) - execution = Execution() - self._executions[message_id] = execution - - # Send the code for execution - # Initial request and retries - for i in range(1 + MAX_RECONNECT_RETRIES): - try: - logger.info( - f"Sending code for the execution ({message_id}): {complete_code}" - ) - request = self._get_execute_request( - message_id, complete_code, False - ) - await self._ws.send(request) - break - except (ConnectionClosedError, WebSocketException) as e: - # Keep the last result, even if error - if i < MAX_RECONNECT_RETRIES: - logger.warning( - f"WebSocket connection lost while sending execution request, {i + 1}. reconnecting...: {str(e)}" - ) - await self.reconnect() - else: - # The retry didn't help, request wasn't sent successfully - logger.error("Failed to send execution request") - await execution.queue.put( - Error( - name="WebSocketError", - value="Failed to send execution request", - traceback="", - ) - ) - await execution.queue.put(UnexpectedEndOfExecution()) - - # Stream the results. - # If the client disconnects (Starlette cancels the task), we - # interrupt the kernel so the next execution isn't blocked (#213). - try: - async for item in self._wait_for_result(message_id): - yield item - except (asyncio.CancelledError, GeneratorExit): - logger.warning( - f"Client disconnected during execution ({message_id}), interrupting kernel" - ) - # Shield the interrupt from the ongoing cancellation so - # the HTTP request to the kernel actually completes. - try: - await asyncio.shield(self.interrupt()) - except asyncio.CancelledError: - pass - raise - finally: - if message_id in self._executions: - del self._executions[message_id] - - # Clean up env vars in a separate request after the main code has run - if env_vars: - self._cleanup_task = asyncio.create_task( - self._cleanup_env_vars(env_vars) - ) - - async def _receive_message(self): - if not self._ws: - logger.error("No WebSocket connection") - return - - try: - async for message in self._ws: - await self._process_message(json.loads(message)) - except Exception as e: - logger.error(f"WebSocket received error while receiving messages: {str(e)}") - finally: - # To prevent infinite hang, we need to cancel all ongoing execution as we could lost results during the reconnect - # Thanks to the locking, there can be either no ongoing execution or just one. - for key, execution in self._executions.items(): - await execution.queue.put( - Error( - name="WebSocketError", - value="The connections was lost, rerun the code to get the results", - traceback="", - ) - ) - await execution.queue.put(UnexpectedEndOfExecution()) - - async def _process_message(self, data: dict): - """ - Process messages from the WebSocket - - Message types: - https://jupyter-client.readthedocs.io/en/stable/messaging.html - - :param data: The message data - """ - if ( - data["msg_type"] == "status" - and data["content"]["execution_state"] == "restarting" - ): - logger.error("Context is restarting") - for execution in self._executions.values(): - await execution.queue.put( - Error( - name="ContextRestarting", - value="Context was restarted", - traceback="", - ) - ) - await execution.queue.put(EndOfExecution()) - return - - parent_msg_ig = data["parent_header"].get("msg_id", None) - if parent_msg_ig is None: - logger.warning("Parent message ID not found. %s", data) - return - - execution = self._executions.get(parent_msg_ig) - if not execution: - return - - queue = execution.queue - if data["msg_type"] == "error": - logger.debug( - f"Execution {parent_msg_ig} finished execution with error: {data['content']['ename']}: {data['content']['evalue']}" - ) - - if execution.errored: - return - - execution.errored = True - await queue.put( - Error( - name=data["content"]["ename"], - value=data["content"]["evalue"], - traceback="".join(data["content"]["traceback"]), - ) - ) - - elif data["msg_type"] == "stream": - if data["content"]["name"] == "stdout": - logger.debug( - f"Execution {parent_msg_ig} received stdout: {data['content']['text']}" - ) - await queue.put( - Stdout( - text=data["content"]["text"], timestamp=data["header"]["date"] - ) - ) - - elif data["content"]["name"] == "stderr": - logger.debug( - f"Execution {parent_msg_ig} received stderr: {data['content']['text']}" - ) - await queue.put( - Stderr( - text=data["content"]["text"], timestamp=data["header"]["date"] - ) - ) - - elif data["msg_type"] in "display_data": - result = Result(is_main_result=False, data=data["content"]["data"]) - logger.debug( - f"Execution {parent_msg_ig} received display data with following formats: {result.formats()}" - ) - await queue.put(result) - - elif data["msg_type"] == "execute_result": - result = Result(is_main_result=True, data=data["content"]["data"]) - logger.debug( - f"Execution {parent_msg_ig} received execution result with following formats: {result.formats()}" - ) - await queue.put(result) - - elif data["msg_type"] == "status": - if data["content"]["execution_state"] == "busy" and execution.in_background: - logger.debug(f"Execution {parent_msg_ig} started execution") - execution.input_accepted = True - - if data["content"]["execution_state"] == "idle": - if execution.input_accepted: - logger.debug(f"Execution {parent_msg_ig} finished execution") - await queue.put(EndOfExecution()) - - elif data["content"]["execution_state"] == "error": - logger.debug(f"Execution {parent_msg_ig} finished execution with error") - await queue.put( - Error( - name=data["content"]["ename"], - value=data["content"]["evalue"], - traceback="".join(data["content"]["traceback"]), - ) - ) - await queue.put(EndOfExecution()) - - elif data["msg_type"] == "execute_reply": - if data["content"]["status"] == "error": - logger.debug(f"Execution {parent_msg_ig} finished execution with error") - - if execution.errored: - return - - execution.errored = True - await queue.put( - Error( - name=data["content"].get("ename", ""), - value=data["content"].get("evalue", ""), - traceback="".join(data["content"].get("traceback", [])), - ) - ) - elif data["content"]["status"] == "abort": - logger.debug(f"Execution {parent_msg_ig} was aborted") - await queue.put( - Error( - name="ExecutionAborted", - value="Execution was aborted", - traceback="", - ) - ) - await queue.put(EndOfExecution()) - elif data["content"]["status"] == "ok": - pass - - elif data["msg_type"] == "execute_input": - logger.debug(f"Input accepted for {parent_msg_ig}") - await queue.put( - NumberOfExecutions(execution_count=data["content"]["execution_count"]) - ) - execution.input_accepted = True - else: - logger.warning(f"[UNHANDLED MESSAGE TYPE]: {data['msg_type']}") - - async def close(self): - logger.debug(f"Closing WebSocket {self.context_id}") - - if self._ws is not None: - await self._ws.close() - - if self._receive_task is not None: - self._receive_task.cancel() - - # Cancel any pending cleanup task - if self._cleanup_task and not self._cleanup_task.done(): - self._cleanup_task.cancel() - try: - await self._cleanup_task - except asyncio.CancelledError: - pass - - for execution in self._executions.values(): - execution.queue.put_nowait(UnexpectedEndOfExecution()) diff --git a/template/server/requirements.txt b/template/server/requirements.txt deleted file mode 100644 index b3e44b71..00000000 --- a/template/server/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -fastapi==0.111.0 -httpx==0.28.1 -websockets==12.0 -uvicorn[standard]==0.30.1 -requests==2.33.0 -pydantic==2.9.1 diff --git a/template/server/stream.py b/template/server/stream.py deleted file mode 100644 index 0ef0195b..00000000 --- a/template/server/stream.py +++ /dev/null @@ -1,40 +0,0 @@ -import json -from typing import Mapping, Optional, AsyncIterable - -from fastapi.encoders import jsonable_encoder -from starlette.background import BackgroundTask -from fastapi.responses import StreamingResponse - - -class StreamingListJsonResponse(StreamingResponse): - """Converts a pydantic model generator into a streaming HTTP Response - that streams a JSON list, one element at a time. - - See https://github.com/tiangolo/fastapi/issues/1978 - """ - - def __init__( - self, - content_generator: AsyncIterable, - status_code: int = 200, - headers: Optional[Mapping[str, str]] = None, - media_type: Optional[str] = None, - background: Optional[BackgroundTask] = None, - ) -> None: - body_iterator = self._encoded_async_generator(content_generator) - - super().__init__( - content=body_iterator, - status_code=status_code, - headers=headers, - media_type=media_type, - background=background, - ) - - async def _encoded_async_generator(self, async_generator: AsyncIterable): - """Converts an asynchronous pydantic model generator - into a streaming JSON list - """ - async for item in async_generator: - yield f"{json.dumps(jsonable_encoder(item))}\n" - yield '{"type": "end_of_execution"}\n' diff --git a/template/server/utils/locks.py b/template/server/utils/locks.py deleted file mode 100644 index f4a5c6ea..00000000 --- a/template/server/utils/locks.py +++ /dev/null @@ -1,18 +0,0 @@ -import asyncio - - -class LockedMap(dict): - def __init__(self): - super().__init__() - self._map_lock = asyncio.Lock() - self._locks = {} - - async def get_lock(self, key): - await self._map_lock.acquire() - if key not in self._locks: - self._locks[key] = asyncio.Lock() - - lock = self._locks[key] - print(f"Lock acquired for {key}") - self._map_lock.release() - return lock diff --git a/template/start-up.sh b/template/start-up.sh deleted file mode 100755 index 0ea0494d..00000000 --- a/template/start-up.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -install -d -m 0700 /run/e2b-jupyter - -function start_code_interpreter() { - /root/.jupyter/jupyter-healthcheck.sh - if [ $? -ne 0 ]; then - echo "Jupyter Server failed to start, aborting." - exit 1 - fi - - cd /root/.server/ - .venv/bin/uvicorn main:app --host 0.0.0.0 --port 49999 --workers 1 --no-access-log --no-use-colors --timeout-keep-alive 640 -} - -echo "Starting Code Interpreter server..." -start_code_interpreter & -MATPLOTLIBRC=/root/.config/matplotlib/.matplotlibrc jupyter server --IdentityProvider.token="" >/dev/null 2>&1 diff --git a/template/startup_scripts/0002_data.py b/template/startup_scripts/0002_data.py deleted file mode 100644 index 3e994487..00000000 --- a/template/startup_scripts/0002_data.py +++ /dev/null @@ -1,85 +0,0 @@ -import sys - -import IPython -from IPython.core.formatters import BaseFormatter, JSONFormatter -from traitlets.traitlets import Unicode, ObjectName - - -class E2BDataFormatter(BaseFormatter): - format_type = Unicode("e2b/data") - - print_method = ObjectName("_repr_e2b_data_") - _return_type = (dict, str) - - def __call__(self, obj): - # IPython invokes every registered formatter for every displayed - # object. Gate on sys.modules so a non-DataFrame output (e.g. an - # int from `1 + 1`) doesn't pay the pandas import cost — a - # pandas.DataFrame can only exist if the user already imported - # pandas. - pandas = sys.modules.get("pandas") - if pandas is None or not isinstance(obj, pandas.DataFrame): - return super().__call__(obj) - - result = obj.to_dict(orient="list") - for key, value in result.items(): - # Check each column's values - result[key] = [ - v.isoformat() if isinstance(v, pandas.Timestamp) else v for v in value - ] - return result - - -class E2BChartFormatter(BaseFormatter): - format_type = Unicode("e2b/chart") - - print_method = ObjectName("_repr_e2b_chart_") - _return_type = (dict, str) - - def __call__(self, obj): - # Same sys.modules gate as E2BDataFormatter: a matplotlib Figure - # can only exist if the user already imported matplotlib. - if sys.modules.get("matplotlib") is None: - return super().__call__(obj) - - from matplotlib.pyplot import Figure - - if not isinstance(obj, Figure): - return super().__call__(obj) - - from e2b_charts import chart_figure_to_dict - - try: - return chart_figure_to_dict(obj) - except: # noqa: E722 - return {} - - -class E2BJSONFormatter(JSONFormatter): - def __call__(self, obj): - if isinstance(obj, (list, dict)): - try: - import orjson - - return orjson.loads( - orjson.dumps( - obj, option=orjson.OPT_SERIALIZE_NUMPY | orjson.OPT_NON_STR_KEYS - ) - ), {"expanded": True} - except TypeError: - pass - - return super().__call__(obj) - - -ip = IPython.get_ipython() -ip.display_formatter.formatters["e2b/data"] = E2BDataFormatter( - parent=ip.display_formatter -) -ip.display_formatter.formatters["e2b/chart"] = E2BChartFormatter( - parent=ip.display_formatter -) - -ip.display_formatter.formatters["application/json"] = E2BJSONFormatter( - parent=ip.display_formatter -) diff --git a/template/startup_scripts/0003_images.py b/template/startup_scripts/0003_images.py deleted file mode 100644 index 4732d77d..00000000 --- a/template/startup_scripts/0003_images.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import Any - -from IPython.core.display_functions import display -from PIL.Image import Image -from PIL.ImageShow import UnixViewer - - -def show_file(self, path: str, **options: Any) -> int: - # To prevent errors from trying to display image without any display - return 0 - - -UnixViewer.show_file = show_file -original_save = Image.save - - -def save(image, fp, format=None, **options): - if isinstance(fp, str): - display(image) - - original_save(image, fp, format, **options) - - -Image.save = save diff --git a/template/systemd/code-interpreter.service b/template/systemd/code-interpreter.service deleted file mode 100644 index 04c165b4..00000000 --- a/template/systemd/code-interpreter.service +++ /dev/null @@ -1,17 +0,0 @@ -[Unit] -Description=Code Interpreter Server -Documentation=https://github.com/e2b-dev/code-interpreter -Requires=jupyter.service -After=jupyter.service -PartOf=jupyter.service -StartLimitBurst=0 - -[Service] -Type=simple -WorkingDirectory=/root/.server -ExecStartPre=/root/.jupyter/jupyter-healthcheck.sh -ExecStart=/root/.server/.venv/bin/uvicorn main:app --host 0.0.0.0 --port 49999 --workers 1 --no-access-log --no-use-colors --timeout-keep-alive 640 -Restart=on-failure -RestartSec=1 -StandardOutput=journal -StandardError=journal diff --git a/template/systemd/jupyter-debug.conf b/template/systemd/jupyter-debug.conf deleted file mode 100644 index 89377a6f..00000000 --- a/template/systemd/jupyter-debug.conf +++ /dev/null @@ -1,5 +0,0 @@ -# Debug-only drop-in: route Jupyter's stdout to the journal (the base unit -# sends it to /dev/null) so ServerApp request/error logs are visible via -# `journalctl -u jupyter`. Applied only by `make_template(debug=True)`. -[Service] -StandardOutput=journal diff --git a/template/systemd/jupyter.service b/template/systemd/jupyter.service deleted file mode 100644 index 178124bd..00000000 --- a/template/systemd/jupyter.service +++ /dev/null @@ -1,17 +0,0 @@ -[Unit] -Description=Jupyter Server -Documentation=https://jupyter-server.readthedocs.io -Wants=code-interpreter.service -StartLimitBurst=0 - -[Service] -Type=simple -RuntimeDirectory=e2b-jupyter -RuntimeDirectoryMode=0700 -Environment=MATPLOTLIBRC=/root/.config/matplotlib/.matplotlibrc -ExecStart=/usr/local/bin/jupyter server --IdentityProvider.token="" -ExecStartPost=-/usr/bin/systemctl reset-failed code-interpreter -Restart=on-failure -RestartSec=1 -StandardOutput=null -StandardError=journal diff --git a/template/template.py b/template/template.py deleted file mode 100644 index fd8dd937..00000000 --- a/template/template.py +++ /dev/null @@ -1,146 +0,0 @@ -from e2b import ReadyCmd, Template, wait_for_url - - -def make_template( - kernels: list[str] = ["python", "r", "javascript", "bash", "java"], - is_docker: bool = False, - ready: ReadyCmd | None = None, - debug: bool = False, -): - enabled_kernels = set(["python", "javascript"] + kernels) - # Start with base template - template = ( - Template() - .from_image("python:3.13") - .set_user("root") - .set_workdir("/root") - .set_envs( - { - "PIP_DEFAULT_TIMEOUT": "100", - "PIP_DISABLE_PIP_VERSION_CHECK": "1", - "PIP_NO_CACHE_DIR": "1", - "JAVA_VERSION": "11", - "JAVA_HOME": "/usr/lib/jvm/jdk-${JAVA_VERSION}", - "IJAVA_VERSION": "1.3.0", - "R_VERSION": "4.5.*", - } - ) - .apt_install( - [ - "build-essential", - "curl", - "git", - "util-linux", - "jq", - "sudo", - "fonts-noto-cjk", - "ca-certificates", - ] - ) - .run_cmd("curl -fsSL https://deb.nodesource.com/setup_20.x | bash -") - .apt_install("nodejs") - .copy("requirements.txt", "requirements.txt") - .pip_install("--no-cache-dir -r requirements.txt") - ) - - if "python" in enabled_kernels: - template = template.run_cmd("ipython kernel install --name 'python3' --user") - - # Install R Kernel if requested - if "r" in enabled_kernels: - template = template.apt_install("r-base=${R_VERSION} r-base-dev").run_cmd( - [ - "R -e \"install.packages('IRkernel', repos='https://cloud.r-project.org')\"", - "R -e \"IRkernel::installspec(user = FALSE, name = 'r', displayname = 'R')\"", - ] - ) - - # Install JavaScript Kernel if requested - if "javascript" in enabled_kernels: - template = template.npm_install( - "--unsafe-perm git+https://github.com/e2b-dev/ijavascript.git", - g=True, - ).run_cmd("ijsinstall --install=global") - - # Install Bash Kernel if requested - if "bash" in enabled_kernels: - template = template.pip_install("bash_kernel").run_cmd( - "python -m bash_kernel.install" - ) - - # Install Java and Java Kernel if requested - if "java" in enabled_kernels: - template = template.run_cmd( - [ - "mkdir -p /usr/lib/jvm", - "curl -fsSL https://download.java.net/java/ga/jdk${JAVA_VERSION}/openjdk-${JAVA_VERSION}_linux-x64_bin.tar.gz | tar -xz -C /usr/lib/jvm", - "update-alternatives --install /usr/bin/java java /usr/lib/jvm/jdk-${JAVA_VERSION}/bin/java 1", - "update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/jdk-${JAVA_VERSION}/bin/javac 1", - "wget https://github.com/SpencerPark/IJava/releases/download/v${IJAVA_VERSION}/ijava-${IJAVA_VERSION}.zip", - "unzip ijava-${IJAVA_VERSION}.zip", - "python install.py --sys-prefix", - ] - ) - - # Common setup steps (always run) - template = ( - template - # Create server virtual environment - .copy("server", ".server") - .run_cmd("python -m venv .server/.venv") - # Copy and install server requirements - .run_cmd( - ".server/.venv/bin/pip install --no-cache-dir -r .server/requirements.txt" - ) - ) - - # Copy configuration files - template = ( - template.copy("matplotlibrc", ".config/matplotlib/.matplotlibrc") - .copy("jupyter-healthcheck.sh", ".jupyter/jupyter-healthcheck.sh") - .run_cmd("chmod +x .jupyter/jupyter-healthcheck.sh") - .copy("jupyter_server_config.py", ".jupyter/") - .make_dir(".ipython/profile_default/startup") - .copy("ipython_kernel_config.py", ".ipython/profile_default/") - .copy("startup_scripts", ".ipython/profile_default/startup") - ) - - if not is_docker: - template = template.copy( - "systemd/jupyter.service", "/etc/systemd/system/jupyter.service" - ).copy( - "systemd/code-interpreter.service", - "/etc/systemd/system/code-interpreter.service", - ) - if debug: - # Drop-in that routes Jupyter's stdout to the journal for debugging. - template = template.copy( - "systemd/jupyter-debug.conf", - "/etc/systemd/system/jupyter.service.d/debug.conf", - ) - else: - template = template.copy("start-up.sh", ".jupyter/start-up.sh").run_cmd( - "chmod +x .jupyter/start-up.sh" - ) - - if is_docker: - # create user user and /home/user - template = template.run_cmd("useradd -m user") - template = template.run_cmd("mkdir -p /home/user") - template = template.run_cmd("chown -R user:user /home/user") - # add to sudoers - template = template.run_cmd( - "echo 'user ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers" - ) - - template = template.set_user("user").set_workdir("/home/user") - - if is_docker: - start_cmd = "sudo --preserve-env=E2B_LOCAL /root/.jupyter/start-up.sh" - else: - start_cmd = "sudo systemctl start jupyter" - - if ready is None: - ready = wait_for_url("http://localhost:49999/health") - - return template.set_start_cmd(start_cmd, ready) diff --git a/tests/.env.example b/tests/.env.example deleted file mode 100644 index c8d7360f..00000000 --- a/tests/.env.example +++ /dev/null @@ -1,7 +0,0 @@ -E2B_API_KEY= -# Optional, defaults to e2b.app -E2B_DOMAIN= -# Template alias/ID to create sandboxes from, defaults to code-interpreter-v1 -E2B_TESTS_TEMPLATE= -# Set to true to run against a local server on http://localhost:49999 (`make start-template-server`) -E2B_DEBUG= diff --git a/tests/README.md b/tests/README.md deleted file mode 100644 index b07ebae9..00000000 --- a/tests/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Code Interpreter HTTP tests - -End-to-end tests for the Code Interpreter template. Sandboxes are created with -the `e2b` SDK from `E2B_TESTS_TEMPLATE` (defaults to `code-interpreter-v1`); -everything else talks to the server's HTTP API on port `49999` directly with -`httpx`, so the server protocol is what's under test, not the SDK. See -`.env.example` for configuration. - -```bash -uv sync --locked -E2B_API_KEY=... uv run pytest -``` - -Set `E2B_DEBUG=true` to run against a local server started with -`make start-template-server`; tests marked `skip_debug` (sandbox provisioning, -optional kernels, recovery) are skipped in that mode. - -A few checks need a shell inside the sandbox (systemd restarts, the private -Jupyter Unix socket in `test_jupyter_socket.py`); those use the SDK's -`sandbox.commands.run` and are otherwise asserted the same way. diff --git a/tests/charts/__init__.py b/tests/charts/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/charts/conftest.py b/tests/charts/conftest.py deleted file mode 100644 index 0ed45166..00000000 --- a/tests/charts/conftest.py +++ /dev/null @@ -1,15 +0,0 @@ -import pytest - -from harness import CodeInterpreter - - -@pytest.fixture() -def run_chart(client: CodeInterpreter): - def run(code: str) -> dict: - execution = client.run_code(code) - assert execution.error is None, execution.error - chart = execution.results[0].chart - assert chart - return chart - - return run diff --git a/tests/charts/test_bar.py b/tests/charts/test_bar.py deleted file mode 100644 index 5f126a79..00000000 --- a/tests/charts/test_bar.py +++ /dev/null @@ -1,43 +0,0 @@ -code = """ -import matplotlib.pyplot as plt - -# Prepare data -authors = ['Author A', 'Author B', 'Author C', 'Author D'] -sales = [100, 200, 300, 400] - -# Create and customize the bar chart -plt.figure(figsize=(10, 6)) -plt.bar(authors, sales, label='Books Sold', color='blue') -plt.xlabel('Authors') -plt.ylabel('Number of Books Sold') -plt.title('Book Sales by Authors') - -# Display the chart -plt.tight_layout() -plt.show() -""" - - -def test_chart_bar(run_chart): - chart = run_chart(code) - - assert chart["type"] == "bar" - assert chart["title"] == "Book Sales by Authors" - - assert chart["x_label"] == "Authors" - assert chart["y_label"] == "Number of Books Sold" - - assert chart["x_unit"] is None - assert chart["y_unit"] is None - - bars = chart["elements"] - assert len(bars) == 4 - - assert [bar["value"] for bar in bars] == [100, 200, 300, 400] - assert [bar["label"] for bar in bars] == [ - "Author A", - "Author B", - "Author C", - "Author D", - ] - assert [bar["group"] for bar in bars] == ["Books Sold"] * 4 diff --git a/tests/charts/test_box_and_whiskers.py b/tests/charts/test_box_and_whiskers.py deleted file mode 100644 index fd978afe..00000000 --- a/tests/charts/test_box_and_whiskers.py +++ /dev/null @@ -1,53 +0,0 @@ -code = """ -import matplotlib.pyplot as plt -import numpy as np - -# Sample data -data = { - 'Class A': [85, 90, 78, 92, 88], - 'Class B': [95, 89, 76, 91, 84, 87], - 'Class C': [75, 82, 88, 79, 86] -} - -# Create figure and axis -fig, ax = plt.subplots(figsize=(10, 6)) - -# Customize plot -ax.set_title('Exam Scores Distribution') -ax.set_xlabel('Class') -ax.set_ylabel('Score') - -# Set custom colors -ax.boxplot(data.values(), labels=data.keys(), patch_artist=True) - -# Add legend -ax.legend() - -# Adjust layout and show plot -plt.tight_layout() -plt.show() -""" - - -def test_box_and_whiskers(run_chart): - chart = run_chart(code) - - assert chart["type"] == "box_and_whisker" - assert chart["title"] == "Exam Scores Distribution" - - assert chart["x_label"] == "Class" - assert chart["y_label"] == "Score" - - assert chart["x_unit"] is None - assert chart["y_unit"] is None - - bars = chart["elements"] - assert len(bars) == 3 - - assert [bar["outliers"] for bar in bars] == [[], [76], []] - assert [bar["min"] for bar in bars] == [78, 84, 75] - assert [bar["first_quartile"] for bar in bars] == [85, 84.75, 79] - assert [bar["median"] for bar in bars] == [88, 88, 82] - assert [bar["third_quartile"] for bar in bars] == [90, 90.5, 86] - assert [bar["max"] for bar in bars] == [92, 95, 88] - assert [bar["label"] for bar in bars] == ["Class A", "Class B", "Class C"] diff --git a/tests/charts/test_line.py b/tests/charts/test_line.py deleted file mode 100644 index 146f81fa..00000000 --- a/tests/charts/test_line.py +++ /dev/null @@ -1,70 +0,0 @@ -import datetime - -code = """ -import numpy as np -import matplotlib.pyplot as plt -import datetime - -# Generate x values -dates = [datetime.date(2023, 9, 1) + datetime.timedelta(seconds=i) for i in range(100)] - -x = np.linspace(0, 2*np.pi, 100) -# Calculate y values -y_sin = np.sin(x) -y_cos = np.cos(x) - -# Create the plot -plt.figure(figsize=(10, 6)) -plt.plot(dates, y_sin, label='sin(x)') -plt.plot(dates, y_cos, label='cos(x)') - -# Add labels and title -plt.xlabel("Time (s)") -plt.ylabel("Amplitude (Hz)") -plt.title('Plot of sin(x) and cos(x)') - -# Display the plot -plt.show() -""" - - -def test_line_chart(run_chart): - chart = run_chart(code) - - assert chart["type"] == "line" - assert chart["title"] == "Plot of sin(x) and cos(x)" - - assert chart["x_label"] == "Time (s)" - assert chart["y_label"] == "Amplitude (Hz)" - - assert chart["x_unit"] == "s" - assert chart["y_unit"] == "Hz" - - assert chart["x_scale"] == "datetime" - assert chart["y_scale"] == "linear" - - assert all(isinstance(x, str) for x in chart["x_ticks"]) - assert isinstance( - datetime.datetime.fromisoformat(chart["x_ticks"][0]), datetime.datetime - ) - assert all(isinstance(y, float) for y in chart["y_ticks"]) - - assert all(isinstance(x, str) for x in chart["x_tick_labels"]) - assert all(isinstance(y, str) for y in chart["y_tick_labels"]) - - lines = chart["elements"] - assert len(lines) == 2 - - first_line = lines[0] - assert first_line["label"] == "sin(x)" - assert len(first_line["points"]) == 100 - assert all( - isinstance(x, str) and isinstance(y, float) for x, y in first_line["points"] - ) - assert isinstance( - datetime.datetime.fromisoformat(first_line["points"][0][0]), datetime.datetime - ) - - second_line = lines[1] - assert second_line["label"] == "cos(x)" - assert len(second_line["points"]) == 100 diff --git a/tests/charts/test_log_chart.py b/tests/charts/test_log_chart.py deleted file mode 100644 index 3c84a95a..00000000 --- a/tests/charts/test_log_chart.py +++ /dev/null @@ -1,55 +0,0 @@ -code = """ -import numpy as np -import matplotlib.pyplot as plt - -# Generate x values -x = np.linspace(0, 100, 100) -# Calculate y values -y = np.exp(x) - -# Create the plot -plt.figure(figsize=(10, 6)) -plt.plot(x, y, label='y = e^x') - -# Set log scale for the y-axis -plt.yscale('log') - -# Add labels and title -plt.xlabel('X-axis') -plt.ylabel('Y-axis (log scale)') -plt.title('Chart with Log Scale on Y-axis') - -plt.legend() -plt.grid(True) -plt.show() -""" - - -def test_log_chart(run_chart): - chart = run_chart(code) - - assert chart["type"] == "line" - assert chart["title"] == "Chart with Log Scale on Y-axis" - - assert chart["x_label"] == "X-axis" - assert chart["y_label"] == "Y-axis (log scale)" - - assert chart["x_unit"] is None - assert chart["y_unit"] == "log scale" - - assert chart["x_scale"] == "linear" - assert chart["y_scale"] == "log" - - assert all(isinstance(x, float) for x in chart["x_ticks"]) - assert all(isinstance(y, float) for y in chart["y_ticks"]) - - assert all(isinstance(x, str) for x in chart["x_tick_labels"]) - assert all(isinstance(y, str) for y in chart["y_tick_labels"]) - - lines = chart["elements"] - assert len(lines) == 1 - - line = lines[0] - assert line["label"] == "y = e^x" - assert len(line["points"]) == 100 - assert all(isinstance(x, float) and isinstance(y, float) for x, y in line["points"]) diff --git a/tests/charts/test_pie.py b/tests/charts/test_pie.py deleted file mode 100644 index 045ee6f9..00000000 --- a/tests/charts/test_pie.py +++ /dev/null @@ -1,43 +0,0 @@ -code = """ -import matplotlib.pyplot as plt -import numpy as np - -# Step 1: Define the data for the pie chart -categories = ["No", "No, in blue"] -sizes = [90, 10] - -# Step 2: Create the figure and axis objects -fig, ax = plt.subplots(figsize=(8, 8)) - -plt.xlabel("x") -plt.ylabel("y") - -# Step 3: Create the pie chart -ax.pie(sizes, labels=categories, autopct='%1.1f%%', startangle=90, colors=plt.cm.Pastel1.colors[:len(categories)]) - -# Step 4: Add title and legend -ax.axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle -plt.title('Will I wake up early tomorrow?') - -# Step 5: Show the plot -plt.show() -""" - - -def test_pie_chart(run_chart): - chart = run_chart(code) - - assert chart["type"] == "pie" - assert chart["title"] == "Will I wake up early tomorrow?" - - assert len(chart["elements"]) == 2 - - first_data = chart["elements"][0] - assert first_data["label"] == "No" - assert first_data["angle"] == 324 - assert first_data["radius"] == 1 - - second_data = chart["elements"][1] - assert second_data["label"] == "No, in blue" - assert second_data["angle"] == 36 - assert second_data["radius"] == 1 diff --git a/tests/charts/test_scale.py b/tests/charts/test_scale.py deleted file mode 100644 index 00da0eda..00000000 --- a/tests/charts/test_scale.py +++ /dev/null @@ -1,42 +0,0 @@ -def test_datetime_scale(run_chart): - chart = run_chart( - """ - import numpy as np - import matplotlib.pyplot as plt - import datetime - - # Generate x values - dates = [datetime.date(2023, 9, 1) + datetime.timedelta(seconds=i) for i in range(100)] - y_sin = np.sin(np.linspace(0, 2*np.pi, 100)) - - # Create the plot - plt.figure(figsize=(10, 6)) - plt.plot(dates, y_sin, label='sin(x)') - plt.show() - """ - ) - - assert chart["type"] == "line" - assert chart["x_scale"] == "datetime" - assert chart["y_scale"] == "linear" - - -def test_categorical_scale(run_chart): - chart = run_chart( - """ - import numpy as np - import matplotlib.pyplot as plt - - x = [1, 2, 3, 4, 5] - y = ['A', 'B', 'C', 'D', 'E'] - - # Create the plot - plt.figure(figsize=(10, 6)) - plt.plot(x, y) - plt.show() - """ - ) - - assert chart["type"] == "line" - assert chart["x_scale"] == "linear" - assert chart["y_scale"] == "categorical" diff --git a/tests/charts/test_scatter.py b/tests/charts/test_scatter.py deleted file mode 100644 index 02c8672e..00000000 --- a/tests/charts/test_scatter.py +++ /dev/null @@ -1,50 +0,0 @@ -code = """ -import matplotlib.pyplot as plt -import numpy as np - -# Create data -N = 5 -x1 = np.random.rand(N) -y1 = np.random.rand(N) -x2 = np.random.rand(2*N) -y2 = np.random.rand(2*N) - -plt.xlabel("A") -plt.ylabel("B") - -plt.scatter(x1, y1, c='blue', label='Dataset 1') -plt.scatter(x2, y2, c='red', label='Dataset 2') - -plt.show() -""" - - -def test_scatter_chart(run_chart): - chart = run_chart(code) - - assert chart["type"] == "scatter" - - assert chart["title"] is None - assert chart["x_label"] == "A" - assert chart["y_label"] == "B" - - assert chart["x_scale"] == "linear" - assert chart["y_scale"] == "linear" - - assert all(isinstance(x, float) for x in chart["x_ticks"]) - assert all(isinstance(y, float) for y in chart["y_ticks"]) - - assert all(isinstance(x, str) for x in chart["x_tick_labels"]) - assert all(isinstance(y, str) for y in chart["y_tick_labels"]) - - assert len(chart["elements"]) == 2 - - first_data = chart["elements"][0] - assert first_data["label"] == "Dataset 1" - assert len(first_data["points"]) == 5 - assert all(len(point) == 2 for point in first_data["points"]) - - second_data = chart["elements"][1] - assert second_data["label"] == "Dataset 2" - assert len(second_data["points"]) == 10 - assert all(len(point) == 2 for point in second_data["points"]) diff --git a/tests/charts/test_superchart.py b/tests/charts/test_superchart.py deleted file mode 100644 index 37a64b9a..00000000 --- a/tests/charts/test_superchart.py +++ /dev/null @@ -1,55 +0,0 @@ -code = """ -import matplotlib.pyplot as plt -import numpy as np - -# Data for plotting -x1 = np.linspace(0, 10, 100) -y1 = np.sin(x1) - -# Create a figure with multiple subplots -fig, axs = plt.subplots(1, 2, figsize=(10, 8)) -fig.suptitle('Multiple Charts Example', fontsize=16) - -# Plotting on the different axes -axs[0].plot(x1, y1, 'r') -axs[0].set_title('Sine Wave') -axs[0].grid(True) - -N = 5 -x2 = np.random.rand(N) -y2 = np.random.rand(N) - -axs[1].scatter(x2, y2, c='blue', label='Dataset 1') -axs[1].set_xlabel('X') -axs[1].set_ylabel('Y') -axs[1].set_title('Scatter Plot') -axs[1].grid(True) - -plt.show() -""" - - -def test_super_chart(run_chart): - chart = run_chart(code) - - assert chart["type"] == "superchart" - assert chart["title"] == "Multiple Charts Example" - - charts = chart["elements"] - assert len(charts) == 2 - - first_chart = charts[0] - assert first_chart["type"] == "line" - assert first_chart["title"] == "Sine Wave" - assert first_chart["x_label"] is None - assert first_chart["y_label"] is None - assert len(first_chart["elements"]) == 1 - assert len(first_chart["elements"][0]["points"]) == 100 - - second_chart = charts[1] - assert second_chart["type"] == "scatter" - assert second_chart["title"] == "Scatter Plot" - assert second_chart["x_label"] == "X" - assert second_chart["y_label"] == "Y" - assert len(second_chart["elements"]) == 1 - assert len(second_chart["elements"][0]["points"]) == 5 diff --git a/tests/charts/test_unknown.py b/tests/charts/test_unknown.py deleted file mode 100644 index fba4273c..00000000 --- a/tests/charts/test_unknown.py +++ /dev/null @@ -1,33 +0,0 @@ -code = """ -import matplotlib.pyplot as plt -import numpy as np - -# Create a figure and an axis -fig, ax = plt.subplots() - -# Create data for two concentric circles -circle1 = plt.Circle((0, 0), 1, color='blue', fill=False, linewidth=2) -circle2 = plt.Circle((0, 0), 2, color='red', fill=False, linewidth=2) - -# Add the circles to the axes -ax.add_artist(circle1) -ax.add_artist(circle2) - -# Set grid -ax.grid(True) - -# Set title -plt.title('Two Concentric Circles') - -# Show the plot -plt.show() -""" - - -def test_unknown_charts(run_chart): - chart = run_chart(code) - - assert chart["type"] == "unknown" - assert chart["title"] == "Two Concentric Circles" - - assert chart["elements"] == [] diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index fc06d9d3..00000000 --- a/tests/conftest.py +++ /dev/null @@ -1,117 +0,0 @@ -import os -import uuid -from typing import Callable, Optional - -import pytest -from dotenv import load_dotenv -from e2b import Sandbox - -from harness import AsyncCodeInterpreter, CodeInterpreter - -load_dotenv() - -DEFAULT_TEST_SANDBOX_TIMEOUT = 120 -CODE_INTERPRETER_PORT = 49999 -LOCAL_SERVER_URL = f"http://localhost:{CODE_INTERPRETER_PORT}" - - -def is_debug() -> bool: - return os.getenv("E2B_DEBUG", "false").lower() == "true" - - -@pytest.fixture(scope="session") -def sandbox_test_id() -> str: - return f"test_{uuid.uuid4()}" - - -@pytest.fixture(scope="session") -def template() -> str: - return os.getenv("E2B_TESTS_TEMPLATE") or "code-interpreter-v1" - - -@pytest.fixture() -def sandbox_factory( - request: pytest.FixtureRequest, template: str, sandbox_test_id: str -) -> Callable[..., Sandbox]: - # Skip lazily, on use: the debug branches of `client`/`async_client` - # depend on this fixture without ever calling it. - def factory( - *, - timeout: int = DEFAULT_TEST_SANDBOX_TIMEOUT, - envs: Optional[dict[str, str]] = None, - allow_public_traffic: bool = True, - ) -> Sandbox: - if is_debug(): - pytest.skip("Sandbox provisioning is not available in debug mode") - sandbox = Sandbox.create( - template, - timeout=timeout, - metadata={"sandbox_test_id": sandbox_test_id}, - envs=envs, - network={"allow_public_traffic": allow_public_traffic}, - ) - request.addfinalizer(sandbox.kill) - return sandbox - - return factory - - -@pytest.fixture() -def sandbox(sandbox_factory) -> Sandbox: - return sandbox_factory() - - -def code_interpreter_url(sandbox: Sandbox) -> str: - scheme = "http" if sandbox.connection_config.debug else "https" - return f"{scheme}://{sandbox.get_host(CODE_INTERPRETER_PORT)}" - - -def make_client(sandbox: Sandbox) -> CodeInterpreter: - return CodeInterpreter( - code_interpreter_url(sandbox), - envd_access_token=sandbox._envd_access_token, - traffic_access_token=sandbox.traffic_access_token, - ) - - -def make_async_client(sandbox: Sandbox) -> AsyncCodeInterpreter: - return AsyncCodeInterpreter( - code_interpreter_url(sandbox), - envd_access_token=sandbox._envd_access_token, - traffic_access_token=sandbox.traffic_access_token, - ) - - -@pytest.fixture() -def client_factory(request: pytest.FixtureRequest, sandbox_factory): - def factory(**sandbox_kwargs) -> CodeInterpreter: - client = make_client(sandbox_factory(**sandbox_kwargs)) - request.addfinalizer(client.close) - return client - - return factory - - -@pytest.fixture() -def client(request: pytest.FixtureRequest, client_factory) -> CodeInterpreter: - if is_debug(): - client = CodeInterpreter(LOCAL_SERVER_URL) - request.addfinalizer(client.close) - return client - return client_factory() - - -@pytest.fixture() -async def async_client(request: pytest.FixtureRequest, sandbox_factory): - if is_debug(): - client = AsyncCodeInterpreter(LOCAL_SERVER_URL) - else: - client = make_async_client(sandbox_factory()) - yield client - await client.aclose() - - -@pytest.fixture(autouse=True) -def skip_debug(request: pytest.FixtureRequest): - if request.node.get_closest_marker("skip_debug") and is_debug(): - pytest.skip("Skipped in debug mode") diff --git a/tests/env_vars/__init__.py b/tests/env_vars/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/env_vars/test_bash.py b/tests/env_vars/test_bash.py deleted file mode 100644 index 3d3b639e..00000000 --- a/tests/env_vars/test_bash.py +++ /dev/null @@ -1,30 +0,0 @@ -import pytest - -from harness import CodeInterpreter - - -@pytest.mark.skip_debug -def test_env_vars_on_sandbox(client_factory): - client = client_factory(envs={"TEST_ENV_VAR": "supertest"}) - execution = client.run_code("echo $TEST_ENV_VAR", language="bash") - assert execution.stdout[0] == "supertest\n" - - -def test_env_vars_per_execution(client: CodeInterpreter): - execution = client.run_code("echo $FOO", envs={"FOO": "bar"}, language="bash") - execution_empty = client.run_code("echo ${FOO:-default}", language="bash") - - assert execution.stdout[0] == "bar\n" - assert execution_empty.stdout[0] == "default\n" - - -@pytest.mark.skip_debug -def test_env_vars_overwrite(client_factory): - client = client_factory(envs={"TEST_ENV_VAR": "supertest"}) - execution = client.run_code( - "echo $TEST_ENV_VAR", language="bash", envs={"TEST_ENV_VAR": "overwrite"} - ) - execution_global_default = client.run_code("echo $TEST_ENV_VAR", language="bash") - - assert execution.stdout[0] == "overwrite\n" - assert execution_global_default.stdout[0] == "supertest\n" diff --git a/tests/env_vars/test_java.py b/tests/env_vars/test_java.py deleted file mode 100644 index e719f298..00000000 --- a/tests/env_vars/test_java.py +++ /dev/null @@ -1,46 +0,0 @@ -import pytest - -from harness import CodeInterpreter - -pytestmark = pytest.mark.skip_debug - - -def test_env_vars_on_sandbox(client_factory): - client = client_factory(envs={"TEST_ENV_VAR": "supertest"}) - client.wait_for_kernel("java") - execution = client.run_code('System.getProperty("TEST_ENV_VAR")', language="java") - assert execution.text is not None - assert execution.text.strip() == "supertest" - - -def test_env_vars_per_execution(client: CodeInterpreter): - client.wait_for_kernel("java") - execution = client.run_code( - 'System.getProperty("FOO")', envs={"FOO": "bar"}, language="java" - ) - execution_empty = client.run_code( - 'System.getProperty("FOO", "default")', language="java" - ) - - assert execution.text is not None - assert execution.text.strip() == "bar" - assert execution_empty.text is not None - assert execution_empty.text.strip() == "default" - - -def test_env_vars_overwrite(client_factory): - client = client_factory(envs={"TEST_ENV_VAR": "supertest"}) - client.wait_for_kernel("java") - execution = client.run_code( - 'System.getProperty("TEST_ENV_VAR")', - language="java", - envs={"TEST_ENV_VAR": "overwrite"}, - ) - execution_global_default = client.run_code( - 'System.getProperty("TEST_ENV_VAR")', language="java" - ) - - assert execution.text is not None - assert execution.text.strip() == "overwrite" - assert execution_global_default.text is not None - assert execution_global_default.text.strip() == "supertest" diff --git a/tests/env_vars/test_js.py b/tests/env_vars/test_js.py deleted file mode 100644 index 93646655..00000000 --- a/tests/env_vars/test_js.py +++ /dev/null @@ -1,43 +0,0 @@ -import pytest - -from harness import CodeInterpreter - - -@pytest.mark.skip_debug -def test_env_vars_on_sandbox(client_factory): - client = client_factory(envs={"TEST_ENV_VAR": "supertest"}) - execution = client.run_code("process.env.TEST_ENV_VAR", language="javascript") - assert execution.text is not None - assert execution.text.strip() == "supertest" - - -def test_env_vars_per_execution(client: CodeInterpreter): - execution = client.run_code( - "process.env.FOO", envs={"FOO": "bar"}, language="javascript" - ) - execution_empty = client.run_code( - "process.env.FOO || 'default'", language="javascript" - ) - - assert execution.text is not None - assert execution.text.strip() == "bar" - assert execution_empty.text is not None - assert execution_empty.text.strip() == "default" - - -@pytest.mark.skip_debug -def test_env_vars_overwrite(client_factory): - client = client_factory(envs={"TEST_ENV_VAR": "supertest"}) - execution = client.run_code( - "process.env.TEST_ENV_VAR", - language="javascript", - envs={"TEST_ENV_VAR": "overwrite"}, - ) - execution_global_default = client.run_code( - "process.env.TEST_ENV_VAR", language="javascript" - ) - - assert execution.text is not None - assert execution.text.strip() == "overwrite" - assert execution_global_default.text is not None - assert execution_global_default.text.strip() == "supertest" diff --git a/tests/env_vars/test_python.py b/tests/env_vars/test_python.py deleted file mode 100644 index 729528d5..00000000 --- a/tests/env_vars/test_python.py +++ /dev/null @@ -1,40 +0,0 @@ -import pytest - -from harness import CodeInterpreter - - -@pytest.mark.skip_debug -def test_env_vars_on_sandbox(client_factory): - client = client_factory(envs={"TEST_ENV_VAR": "supertest"}) - execution = client.run_code( - "import os; os.getenv('TEST_ENV_VAR')", language="python" - ) - assert execution.text == "supertest" - - -def test_env_vars_per_execution(client: CodeInterpreter): - execution = client.run_code( - "import os; os.getenv('FOO')", envs={"FOO": "bar"}, language="python" - ) - execution_empty = client.run_code( - "import os; os.getenv('FOO', 'default')", language="python" - ) - - assert execution.text == "bar" - assert execution_empty.text == "default" - - -@pytest.mark.skip_debug -def test_env_vars_overwrite(client_factory): - client = client_factory(envs={"TEST_ENV_VAR": "supertest"}) - execution = client.run_code( - "import os; os.getenv('TEST_ENV_VAR')", - language="python", - envs={"TEST_ENV_VAR": "overwrite"}, - ) - execution_global_default = client.run_code( - "import os; os.getenv('TEST_ENV_VAR')", language="python" - ) - - assert execution.text == "overwrite" - assert execution_global_default.text == "supertest" diff --git a/tests/env_vars/test_r.py b/tests/env_vars/test_r.py deleted file mode 100644 index c16568dc..00000000 --- a/tests/env_vars/test_r.py +++ /dev/null @@ -1,38 +0,0 @@ -import pytest - -from harness import CodeInterpreter - - -@pytest.mark.skip_debug -def test_env_vars_on_sandbox(client_factory): - client = client_factory(envs={"TEST_ENV_VAR": "supertest"}) - client.wait_for_kernel("r") - execution = client.run_code("Sys.getenv('TEST_ENV_VAR')", language="r") - assert execution.results[0].text.strip() == '[1] "supertest"' - - -@pytest.mark.skip_debug -def test_env_vars_per_execution(client: CodeInterpreter): - client.wait_for_kernel("r") - execution = client.run_code("Sys.getenv('FOO')", envs={"FOO": "bar"}, language="r") - execution_empty = client.run_code( - "Sys.getenv('FOO', unset = 'default')", language="r" - ) - - assert execution.results[0].text.strip() == '[1] "bar"' - assert execution_empty.results[0].text.strip() == '[1] "default"' - - -@pytest.mark.skip_debug -def test_env_vars_overwrite(client_factory): - client = client_factory(envs={"TEST_ENV_VAR": "supertest"}) - client.wait_for_kernel("r") - execution = client.run_code( - "Sys.getenv('TEST_ENV_VAR')", language="r", envs={"TEST_ENV_VAR": "overwrite"} - ) - execution_global_default = client.run_code( - "Sys.getenv('TEST_ENV_VAR')", language="r" - ) - - assert execution.results[0].text.strip() == '[1] "overwrite"' - assert execution_global_default.results[0].text.strip() == '[1] "supertest"' diff --git a/tests/harness/__init__.py b/tests/harness/__init__.py deleted file mode 100644 index b1e89772..00000000 --- a/tests/harness/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -from .code_interpreter import ( - AsyncCodeInterpreter, - CodeInterpreter, - CodeInterpreterError, - Execution, - ExecutionError, - Result, -) - -__all__ = [ - "AsyncCodeInterpreter", - "CodeInterpreter", - "CodeInterpreterError", - "Execution", - "ExecutionError", - "Result", -] diff --git a/tests/harness/code_interpreter.py b/tests/harness/code_interpreter.py deleted file mode 100644 index 88a2912f..00000000 --- a/tests/harness/code_interpreter.py +++ /dev/null @@ -1,303 +0,0 @@ -"""httpx client for the Code Interpreter HTTP API (port 49999). - -Mirrors the wire protocol only: JSON requests and a newline-delimited JSON -stream of output events terminated by ``{"type": "end_of_execution"}``. -""" - -import json -import textwrap -from dataclasses import dataclass, field -from typing import AsyncIterator, Iterator, Optional - -import httpx - -KERNEL_READINESS_ATTEMPTS = 4 -DEFAULT_EXECUTION_TIMEOUT = 60 -DEFAULT_REQUEST_TIMEOUT = 30 - -DATA_FORMATS = ( - "text", - "html", - "markdown", - "svg", - "png", - "jpeg", - "pdf", - "latex", - "json", - "javascript", - "data", - "chart", -) - - -class CodeInterpreterError(Exception): - def __init__(self, response: httpx.Response): - self.status_code = response.status_code - self.body = response.text - super().__init__( - f"{response.status_code} {response.reason_phrase}: {self.body}" - ) - - -@dataclass -class Result: - raw: dict - - def __getattr__(self, name: str): - if name in DATA_FORMATS or name in ("extra", "is_main_result"): - return self.raw.get(name) - raise AttributeError(name) - - def formats(self) -> list[str]: - return [fmt for fmt in DATA_FORMATS if self.raw.get(fmt) is not None] - - -@dataclass -class ExecutionError: - name: str - value: str - traceback: str - - -@dataclass -class Execution: - events: list[dict] = field(default_factory=list) - results: list[Result] = field(default_factory=list) - stdout: list[str] = field(default_factory=list) - stderr: list[str] = field(default_factory=list) - error: Optional[ExecutionError] = None - execution_count: Optional[int] = None - completed: bool = False - - @property - def text(self) -> Optional[str]: - for result in self.results: - if result.is_main_result: - return result.text - return None - - def add(self, event: dict) -> None: - self.events.append(event) - kind = event["type"] - if kind == "stdout": - self.stdout.append(event["text"]) - elif kind == "stderr": - self.stderr.append(event["text"]) - elif kind == "result": - self.results.append(Result({k: v for k, v in event.items() if k != "type"})) - elif kind == "error": - self.error = ExecutionError( - name=event["name"], value=event["value"], traceback=event["traceback"] - ) - elif kind == "number_of_executions": - self.execution_count = event["execution_count"] - elif kind == "end_of_execution": - self.completed = True - - @classmethod - def from_events(cls, events) -> "Execution": - execution = cls() - for event in events: - execution.add(event) - return execution - - -def _headers( - envd_access_token: Optional[str], traffic_access_token: Optional[str] -) -> dict[str, str]: - headers = {} - if envd_access_token: - headers["X-Access-Token"] = envd_access_token - if traffic_access_token: - headers["E2B-Traffic-Access-Token"] = traffic_access_token - return headers - - -def _execute_body( - code: str, - language: Optional[str], - context_id: Optional[str], - envs: Optional[dict[str, str]], -) -> dict: - return { - "code": textwrap.dedent(code), - "language": language, - "context_id": context_id, - "env_vars": envs, - } - - -def _is_readiness_error(error: Exception) -> bool: - return isinstance(error, CodeInterpreterError) and error.status_code == 500 - - -class CodeInterpreter: - def __init__( - self, - base_url: str, - *, - envd_access_token: Optional[str] = None, - traffic_access_token: Optional[str] = None, - ): - self.base_url = base_url - self._client = httpx.Client( - base_url=base_url, - headers=_headers(envd_access_token, traffic_access_token), - timeout=DEFAULT_REQUEST_TIMEOUT, - ) - - def close(self) -> None: - self._client.close() - - def health(self, timeout: float = DEFAULT_REQUEST_TIMEOUT) -> httpx.Response: - return self._client.get("/health", timeout=timeout) - - def stream_code( - self, - code: str, - *, - language: Optional[str] = None, - context_id: Optional[str] = None, - envs: Optional[dict[str, str]] = None, - timeout: float = DEFAULT_EXECUTION_TIMEOUT, - ) -> Iterator[dict]: - with self._client.stream( - "POST", - "/execute", - json=_execute_body(code, language, context_id, envs), - timeout=httpx.Timeout(timeout, connect=DEFAULT_REQUEST_TIMEOUT), - ) as response: - if response.status_code >= 400: - response.read() - raise CodeInterpreterError(response) - for line in response.iter_lines(): - if line: - yield json.loads(line) - - def run_code( - self, - code: str, - *, - language: Optional[str] = None, - context_id: Optional[str] = None, - envs: Optional[dict[str, str]] = None, - timeout: float = DEFAULT_EXECUTION_TIMEOUT, - ) -> Execution: - return Execution.from_events( - self.stream_code( - code, - language=language, - context_id=context_id, - envs=envs, - timeout=timeout, - ) - ) - - def wait_for_kernel(self, language: str) -> None: - for attempt in range(KERNEL_READINESS_ATTEMPTS): - try: - self.run_code("1", language=language) - return - except CodeInterpreterError as error: - if ( - not _is_readiness_error(error) - or attempt == KERNEL_READINESS_ATTEMPTS - 1 - ): - raise - - def _check(self, response: httpx.Response) -> httpx.Response: - if response.status_code >= 400: - raise CodeInterpreterError(response) - return response - - def create_context( - self, *, language: Optional[str] = None, cwd: Optional[str] = None - ) -> dict: - body = {} - if language is not None: - body["language"] = language - if cwd is not None: - body["cwd"] = cwd - return self._check(self._client.post("/contexts", json=body)).json() - - def list_contexts(self) -> list[dict]: - return self._check(self._client.get("/contexts")).json() - - def restart_context(self, context_id: str) -> None: - self._check(self._client.post(f"/contexts/{context_id}/restart")) - - def remove_context(self, context_id: str) -> None: - self._check(self._client.delete(f"/contexts/{context_id}")) - - -class AsyncCodeInterpreter: - def __init__( - self, - base_url: str, - *, - envd_access_token: Optional[str] = None, - traffic_access_token: Optional[str] = None, - ): - self.base_url = base_url - self._client = httpx.AsyncClient( - base_url=base_url, - headers=_headers(envd_access_token, traffic_access_token), - timeout=DEFAULT_REQUEST_TIMEOUT, - ) - - async def aclose(self) -> None: - await self._client.aclose() - - async def health(self, timeout: float = DEFAULT_REQUEST_TIMEOUT) -> httpx.Response: - return await self._client.get("/health", timeout=timeout) - - async def stream_code( - self, - code: str, - *, - language: Optional[str] = None, - context_id: Optional[str] = None, - envs: Optional[dict[str, str]] = None, - timeout: float = DEFAULT_EXECUTION_TIMEOUT, - ) -> AsyncIterator[dict]: - async with self._client.stream( - "POST", - "/execute", - json=_execute_body(code, language, context_id, envs), - timeout=httpx.Timeout(timeout, connect=DEFAULT_REQUEST_TIMEOUT), - ) as response: - if response.status_code >= 400: - await response.aread() - raise CodeInterpreterError(response) - async for line in response.aiter_lines(): - if line: - yield json.loads(line) - - async def run_code( - self, - code: str, - *, - language: Optional[str] = None, - context_id: Optional[str] = None, - envs: Optional[dict[str, str]] = None, - timeout: float = DEFAULT_EXECUTION_TIMEOUT, - ) -> Execution: - execution = Execution() - async for event in self.stream_code( - code, language=language, context_id=context_id, envs=envs, timeout=timeout - ): - execution.add(event) - return execution - - async def wait_for_kernel(self, language: str) -> None: - for attempt in range(KERNEL_READINESS_ATTEMPTS): - try: - await self.run_code("1", language=language) - return - except CodeInterpreterError as error: - if ( - not _is_readiness_error(error) - or attempt == KERNEL_READINESS_ATTEMPTS - 1 - ): - raise diff --git a/tests/package.json b/tests/package.json deleted file mode 100644 index e8762061..00000000 --- a/tests/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "@e2b/code-interpreter-tests", - "private": true, - "version": "0.0.0", - "scripts": { - "test": "uv run pytest --verbose", - "pretest": "uv sync --locked", - "lint": "uv run ruff check .", - "format": "uv run ruff format ." - } -} diff --git a/tests/pyproject.toml b/tests/pyproject.toml deleted file mode 100644 index 1fd6edb2..00000000 --- a/tests/pyproject.toml +++ /dev/null @@ -1,28 +0,0 @@ -[project] -name = "e2b-code-interpreter-tests" -version = "0.0.0" -description = "HTTP-level test suite for the E2B Code Interpreter template" -requires-python = ">=3.10" -dependencies = [ - "e2b>=2.32.0,<3", - "httpx>=0.28.1,<1", - "pytest>=9.0.3,<10", - "pytest-asyncio>=1.3.0,<2", - "pytest-dotenv>=0.5.2,<0.6", - "pytest-xdist>=3.6.1,<4", - "python-dotenv>=1.2.1,<2", - "ruff>=0.11.12,<0.12", -] - -[tool.uv] -package = false - -[tool.pytest.ini_options] -asyncio_mode = "auto" -asyncio_default_fixture_loop_scope = "session" -asyncio_default_test_loop_scope = "session" -addopts = ["--import-mode=importlib", "--numprocesses=2"] -pythonpath = ["."] -markers = [ - "skip_debug: skip when running against a local template server (E2B_DEBUG=true)", -] diff --git a/tests/test_async.py b/tests/test_async.py deleted file mode 100644 index 975e0947..00000000 --- a/tests/test_async.py +++ /dev/null @@ -1,46 +0,0 @@ -import asyncio - -import httpx -import pytest - -from harness import AsyncCodeInterpreter - - -async def test_async_basic(async_client: AsyncCodeInterpreter): - execution = await async_client.run_code("x =1; x") - assert execution.text == "1" - - -async def test_async_streaming(async_client: AsyncCodeInterpreter): - events = [event async for event in async_client.stream_code("print(1); 2")] - - assert [event["type"] for event in events] == [ - "number_of_executions", - "stdout", - "result", - "end_of_execution", - ] - assert events[1]["text"] == "1\n" - assert events[2]["text"] == "2" - - -async def test_async_concurrent_executions(async_client: AsyncCodeInterpreter): - executions = await asyncio.gather( - async_client.run_code("import time; time.sleep(1); 'python'"), - async_client.run_code( - "await new Promise(r => setTimeout(r, 1000)); 'js'", language="js" - ), - ) - - assert executions[0].text == "python" - assert executions[1].text == "js" - - -async def test_async_interrupt(async_client: AsyncCodeInterpreter): - with pytest.raises(httpx.TimeoutException): - await async_client.run_code("import time; time.sleep(300)", timeout=3) - - await asyncio.sleep(5) - - execution = await async_client.run_code("1 + 1", timeout=10) - assert execution.text == "2" diff --git a/tests/test_basic.py b/tests/test_basic.py deleted file mode 100644 index 62d3d3d6..00000000 --- a/tests/test_basic.py +++ /dev/null @@ -1,75 +0,0 @@ -import pytest -from e2b import Sandbox - -from conftest import make_client -from harness import CodeInterpreter - - -def test_health(client: CodeInterpreter): - response = client.health() - assert response.status_code == 200 - assert response.json() == "OK" - - -def test_basic(client: CodeInterpreter): - execution = client.run_code("x =1; x") - assert execution.text == "1" - assert execution.completed - - -def test_stateful(client: CodeInterpreter): - client.run_code("test_stateful = 1") - - execution = client.run_code("test_stateful+=1; test_stateful") - assert execution.text == "2" - - -def test_stdout(client: CodeInterpreter): - execution = client.run_code("print('Hello from e2b')") - assert execution.stdout == ["Hello from e2b\n"] - - -def test_stderr(client: CodeInterpreter): - execution = client.run_code( - 'import sys;print("This is an error message", file=sys.stderr)' - ) - assert execution.stderr == ["This is an error message\n"] - - -def test_error(client: CodeInterpreter): - execution = client.run_code("xyz") - assert execution.error is not None - assert execution.error.name == "NameError" - assert execution.error.value == "name 'xyz' is not defined" - assert "NameError" in execution.error.traceback - - -def test_bash_magic(client: CodeInterpreter): - execution = client.run_code("!pwd") - assert "".join(execution.stdout).strip() == "/home/user" - - -@pytest.mark.skip_debug -def test_execution_count(client: CodeInterpreter): - client.run_code("echo 'E2B is awesome!'") - execution = client.run_code("!pwd") - assert execution.execution_count == 2 - - -@pytest.mark.skip_debug -def test_secure_access(client_factory): - client = client_factory(allow_public_traffic=False) - execution = client.run_code("x =1; x") - assert execution.text == "1" - - -@pytest.mark.skip_debug -def test_reconnected_sandbox_keeps_state(sandbox: Sandbox): - first = make_client(sandbox) - first.run_code("x = 1") - first.close() - - second = make_client(Sandbox.connect(sandbox.sandbox_id)) - execution = second.run_code("x") - second.close() - assert execution.text == "1" diff --git a/tests/test_contexts.py b/tests/test_contexts.py deleted file mode 100644 index 8c2c4764..00000000 --- a/tests/test_contexts.py +++ /dev/null @@ -1,118 +0,0 @@ -import pytest - -from harness import CodeInterpreter, CodeInterpreterError - - -def test_create_context_with_no_options(client: CodeInterpreter): - context = client.create_context() - - assert context["language"] == "python" - assert context["cwd"] == "/home/user" - assert client.list_contexts()[-1] == context - - -def test_create_context_with_options(client: CodeInterpreter): - context = client.create_context(language="python", cwd="/root") - - assert context["language"] == "python" - assert context["cwd"] == "/root" - assert client.list_contexts()[-1] == context - - -@pytest.mark.parametrize( - ("alias", "language"), [("js", "javascript"), ("ts", "typescript")] -) -def test_create_context_normalizes_language_alias( - client: CodeInterpreter, alias: str, language: str -): - context = client.create_context(language=alias) - assert context["language"] == language - - -def test_remove_context(client: CodeInterpreter): - context = client.create_context() - - client.remove_context(context["id"]) - - assert context["id"] not in [ctx["id"] for ctx in client.list_contexts()] - - -def test_list_contexts(client: CodeInterpreter): - languages = [context["language"] for context in client.list_contexts()] - assert "python" in languages - assert "javascript" in languages - - -def test_restart_context(client: CodeInterpreter): - context = client.create_context() - - client.run_code("x = 1", context_id=context["id"]) - client.restart_context(context["id"]) - - execution = client.run_code("x", context_id=context["id"]) - assert execution.error is not None - assert execution.error.name == "NameError" - assert execution.error.value == "name 'x' is not defined" - - -def test_independence_of_contexts(client: CodeInterpreter): - context = client.create_context() - client.run_code("x = 1") - - execution = client.run_code("x", context_id=context["id"]) - assert execution.error is not None - assert execution.error.value == "name 'x' is not defined" - - -def test_pass_context_and_language(client: CodeInterpreter): - context = client.create_context(language="python") - - with pytest.raises(CodeInterpreterError) as error: - client.run_code( - "console.log('Hello, World!')", language="js", context_id=context["id"] - ) - - assert error.value.status_code == 400 - assert "Only one of context_id or language" in error.value.body - - -def test_unknown_context(client: CodeInterpreter): - with pytest.raises(CodeInterpreterError) as error: - client.run_code("1", context_id="does-not-exist") - - assert error.value.status_code == 404 - - -def test_restart_unknown_context(client: CodeInterpreter): - with pytest.raises(CodeInterpreterError) as error: - client.restart_context("does-not-exist") - - assert error.value.status_code == 404 - - -def test_remove_unknown_context(client: CodeInterpreter): - with pytest.raises(CodeInterpreterError) as error: - client.remove_context("does-not-exist") - - assert error.value.status_code == 404 - - -@pytest.mark.skip_debug -def test_contexts_secure_traffic(client_factory): - client = client_factory(allow_public_traffic=False) - - languages = [context["language"] for context in client.list_contexts()] - assert "python" in languages - assert "javascript" in languages - - context = client.create_context() - assert client.list_contexts()[-1] == context - - client.run_code("x = 1", context_id=context["id"]) - client.restart_context(context["id"]) - execution = client.run_code("x", context_id=context["id"]) - assert execution.error is not None - assert execution.error.name == "NameError" - - client.remove_context(context["id"]) - assert context["id"] not in [ctx["id"] for ctx in client.list_contexts()] diff --git a/tests/test_cwd.py b/tests/test_cwd.py deleted file mode 100644 index ba5274a2..00000000 --- a/tests/test_cwd.py +++ /dev/null @@ -1,43 +0,0 @@ -import pytest - -from harness import CodeInterpreter - -pytestmark = pytest.mark.skip_debug - - -def test_cwd_python(client: CodeInterpreter): - execution = client.run_code("from pathlib import Path; print(Path.cwd())") - assert "".join(execution.stdout).strip() == "/home/user" - - -def test_cwd_javascript(client: CodeInterpreter): - execution = client.run_code("process.cwd()", language="js") - assert execution.text == "/home/user" - - -def test_cwd_typescript(client: CodeInterpreter): - execution = client.run_code("process.cwd()", language="ts") - assert execution.text == "/home/user" - - -def test_cwd_r(client: CodeInterpreter): - client.wait_for_kernel("r") - execution = client.run_code("getwd()", language="r") - assert execution.results[0].text.strip() == '[1] "/home/user"' - - -def test_cwd_java(client: CodeInterpreter): - client.wait_for_kernel("java") - execution = client.run_code('System.getProperty("user.dir")', language="java") - assert execution.results[0].text.strip() == "/home/user" - - -def test_cwd_bash(client: CodeInterpreter): - execution = client.run_code("pwd", language="bash") - assert "".join(execution.stdout).strip() == "/home/user" - - -def test_custom_cwd_context(client: CodeInterpreter): - context = client.create_context(language="python", cwd="/tmp") - execution = client.run_code("import os; os.getcwd()", context_id=context["id"]) - assert execution.text == "/tmp" diff --git a/tests/test_interrupt.py b/tests/test_interrupt.py deleted file mode 100644 index cda1de46..00000000 --- a/tests/test_interrupt.py +++ /dev/null @@ -1,20 +0,0 @@ -import time - -import httpx -import pytest - -from harness import CodeInterpreter - - -def test_subsequent_execution_works_after_client_timeout(client: CodeInterpreter): - # Start a long-running execution with a short client timeout. - # Closing the connection should trigger the server to interrupt the - # kernel (#213) instead of leaving it busy. - with pytest.raises(httpx.TimeoutException): - client.run_code("import time; time.sleep(300)", timeout=3) - - # Give the server time to detect the disconnect and interrupt the kernel. - time.sleep(5) - - execution = client.run_code("1 + 1", timeout=10) - assert execution.text == "2" diff --git a/tests/test_jupyter_socket.py b/tests/test_jupyter_socket.py deleted file mode 100644 index ae204009..00000000 --- a/tests/test_jupyter_socket.py +++ /dev/null @@ -1,42 +0,0 @@ -import pytest -from e2b import CommandExitException, Sandbox - -from conftest import make_client - -pytestmark = pytest.mark.skip_debug - -SOCKET_DIR = "/run/e2b-jupyter" -SOCKET_PATH = f"{SOCKET_DIR}/server.sock" -CURL_STATUS = ( - f"curl -s -o /dev/null -w '%{{http_code}}' --unix-socket {SOCKET_PATH} " - "http://localhost/api/status" -) - - -def test_socket_is_private_to_root(sandbox: Sandbox): - result = sandbox.commands.run( - f"stat -c '%a %U' {SOCKET_DIR} {SOCKET_PATH}", user="root" - ) - assert result.stdout.split("\n")[:2] == ["700 root", "600 root"] - - -def test_jupyter_api_is_served_over_the_socket(sandbox: Sandbox): - assert sandbox.commands.run(CURL_STATUS, user="root").stdout == "200" - - -def test_socket_is_not_reachable_by_user(sandbox: Sandbox): - with pytest.raises(CommandExitException) as error: - sandbox.commands.run(CURL_STATUS, user="user") - assert error.value.exit_code == 7 # curl: failed to connect - - -def test_jupyter_has_no_tcp_listener(sandbox: Sandbox): - listeners = sandbox.commands.run("ss -ltnH", user="root").stdout - assert ":8888" not in listeners - - # The kernel runs inside the sandbox, so this is the loopback view - # jupyter-server's TCP port would be exposed on. - execution = make_client(sandbox).run_code( - "import socket\nsocket.socket().connect_ex(('127.0.0.1', 8888)) != 0" - ) - assert execution.text == "True" diff --git a/tests/test_kernels.py b/tests/test_kernels.py deleted file mode 100644 index bc3893f9..00000000 --- a/tests/test_kernels.py +++ /dev/null @@ -1,52 +0,0 @@ -import pytest - -from harness import CodeInterpreter - - -def test_js_kernel(client: CodeInterpreter): - execution = client.run_code("console.log('Hello, World!')", language="js") - assert execution.stdout == ["Hello, World!\n"] - - -def test_js_esm_imports(client: CodeInterpreter): - execution = client.run_code( - """ - import { readFileSync } from 'fs' - console.log(typeof readFileSync) - """, - language="js", - ) - assert execution.stdout == ["function\n"] - - -def test_js_top_level_await(client: CodeInterpreter): - execution = client.run_code("await Promise.resolve('Hello World!')", language="js") - assert execution.text == "Hello World!" - - -@pytest.mark.skip_debug -def test_ts_kernel(client: CodeInterpreter): - execution = client.run_code( - "const message: string = 'Hello, World!'; console.log(message)", language="ts" - ) - assert execution.stdout == ["Hello, World!\n"] - - -@pytest.mark.skip_debug -def test_r_kernel(client: CodeInterpreter): - client.wait_for_kernel("r") - execution = client.run_code('print("Hello, World!")', language="r") - assert execution.stdout == ['[1] "Hello, World!"\n'] - - -@pytest.mark.skip_debug -def test_java_kernel(client: CodeInterpreter): - client.wait_for_kernel("java") - execution = client.run_code('System.out.println("Hello, World!")', language="java") - assert execution.stdout[0] == "Hello, World!" - - -@pytest.mark.skip_debug -def test_bash_kernel(client: CodeInterpreter): - execution = client.run_code("echo 'Hello, World!'", language="bash") - assert execution.stdout == ["Hello, World!\n"] diff --git a/tests/test_killed.py b/tests/test_killed.py deleted file mode 100644 index 3e9d3b3b..00000000 --- a/tests/test_killed.py +++ /dev/null @@ -1,42 +0,0 @@ -import threading -import time - -import httpx -import pytest -from e2b import Sandbox - -from conftest import make_client -from harness import Execution - - -@pytest.mark.skip_debug -def test_execution_ends_when_sandbox_is_killed(sandbox: Sandbox): - client = make_client(sandbox) - kill_error: list[BaseException] = [] - - def kill(): - try: - sandbox.kill() - except BaseException as error: # surfaced below, Timer swallows it - kill_error.append(error) - - timer = threading.Timer(2.0, kill) - timer.start() - - execution = Execution() - started = time.monotonic() - try: - # The sleep is far longer than the kill delay, so the only thing that - # can end the request is the sandbox being killed; the client timeout - # just keeps a failed kill from hanging the test. - with pytest.raises(httpx.HTTPError): - for event in client.stream_code("import time; time.sleep(300)", timeout=60): - execution.add(event) - finally: - timer.join() - client.close() - - assert not kill_error, kill_error - assert time.monotonic() - started < 60 - assert not execution.completed - assert not sandbox.is_running() diff --git a/tests/test_results.py b/tests/test_results.py deleted file mode 100644 index 9faa8502..00000000 --- a/tests/test_results.py +++ /dev/null @@ -1,111 +0,0 @@ -from harness import CodeInterpreter - - -def test_display_data(client: CodeInterpreter): - execution = client.run_code( - """ - import matplotlib.pyplot as plt - import numpy as np - - x = np.linspace(0, 20, 100) - y = np.sin(x) - - plt.plot(x, y) - plt.show() - """ - ) - - result = execution.results[0] - assert result.png - assert result.text - assert not result.extra - - -def test_data(client: CodeInterpreter): - execution = client.run_code( - """ - import pandas as pd - pd.DataFrame({"a": [1, 2, 3]}) - """ - ) - - result = execution.results[0] - assert result.data - assert "a" in result.data - assert len(result.data["a"]) == 3 - - -def test_custom_repr_object(client: CodeInterpreter): - execution = client.run_code( - """ - from IPython.display import display - - display({'text/latex': r'\\text{CustomReprObject}'}, raw=True) - """ - ) - - assert execution.results[0].formats() == ["latex"] - assert execution.results[0].latex == r"\text{CustomReprObject}" - - -def test_html_result(client: CodeInterpreter): - execution = client.run_code( - """ - from IPython.display import HTML - HTML('bold') - """ - ) - - result = execution.results[0] - assert result.html == "bold" - assert result.is_main_result is True - - -def test_show_image(client: CodeInterpreter): - execution = client.run_code( - """ - import numpy - from PIL import Image - - imarray = numpy.random.rand(16,16,3) * 255 - image = Image.fromarray(imarray.astype('uint8')).convert('RGBA') - - image.show() - print("Image shown.") - """ - ) - - assert execution.results[0].png - - -def test_image_as_last_command(client: CodeInterpreter): - execution = client.run_code( - """ - import numpy - from PIL import Image - - imarray = numpy.random.rand(16,16,3) * 255 - image = Image.fromarray(imarray.astype('uint8')).convert('RGBA') - - image - """ - ) - - assert execution.results[0].png - - -def test_get_image_on_save(client: CodeInterpreter): - execution = client.run_code( - """ - import numpy - from PIL import Image - - imarray = numpy.random.rand(16,16,3) * 255 - image = Image.fromarray(imarray.astype('uint8')).convert('RGBA') - - image.save("test.png") - print("Image saved.") - """ - ) - - assert execution.results[0].png diff --git a/tests/test_streaming.py b/tests/test_streaming.py deleted file mode 100644 index c209461e..00000000 --- a/tests/test_streaming.py +++ /dev/null @@ -1,70 +0,0 @@ -from harness import CodeInterpreter - - -def _types(events: list[dict]) -> list[str]: - return [event["type"] for event in events] - - -def test_streaming_stdout(client: CodeInterpreter): - events = list(client.stream_code("print(1)")) - - stdout = [event for event in events if event["type"] == "stdout"] - assert len(stdout) == 1 - assert stdout[0]["text"] == "1\n" - assert "timestamp" in stdout[0] - assert events[-1] == {"type": "end_of_execution"} - - -def test_streaming_stderr(client: CodeInterpreter): - events = list(client.stream_code("import sys;print(1, file=sys.stderr)")) - - stderr = [event for event in events if event["type"] == "stderr"] - assert len(stderr) == 1 - assert stderr[0]["text"] == "1\n" - - -def test_streaming_result(client: CodeInterpreter): - code = """ - import matplotlib.pyplot as plt - import numpy as np - - x = np.linspace(0, 20, 100) - y = np.sin(x) - - plt.plot(x, y) - plt.show() - - x - """ - - events = list(client.stream_code(code)) - - results = [event for event in events if event["type"] == "result"] - assert len(results) == 2 - assert results[0]["is_main_result"] is False - assert results[1]["is_main_result"] is True - - -def test_event_order(client: CodeInterpreter): - events = list(client.stream_code("print('a'); 1")) - - assert _types(events) == [ - "number_of_executions", - "stdout", - "result", - "end_of_execution", - ] - - -def test_stdout_streams_before_execution_finishes(client: CodeInterpreter): - import time - - arrival = [] - for event in client.stream_code( - "import time; print('a'); time.sleep(2); print('b')" - ): - if event["type"] == "stdout": - arrival.append((event["text"], time.monotonic())) - - assert [text for text, _ in arrival] == ["a\n", "b\n"] - assert arrival[1][1] - arrival[0][1] >= 1.5 diff --git a/tests/test_systemd.py b/tests/test_systemd.py deleted file mode 100644 index 16780745..00000000 --- a/tests/test_systemd.py +++ /dev/null @@ -1,45 +0,0 @@ -import time - -import httpx -import pytest -from e2b import Sandbox - -from conftest import make_client -from harness import CodeInterpreter - -pytestmark = pytest.mark.skip_debug - - -def wait_for_health(client: CodeInterpreter, max_retries=10, interval_ms=100) -> bool: - for _ in range(max_retries): - try: - if client.health(timeout=5).status_code == 200: - return True - except httpx.HTTPError: - pass - time.sleep(interval_ms / 1000) - return False - - -def kill_process(sandbox: Sandbox, pattern: str) -> None: - # The command handle may get killed too (killing jupyter cascades to the - # code-interpreter service), so errors are ignored. - try: - sandbox.commands.run(f"kill -9 $(pgrep -f '{pattern}')", user="root") - except Exception: - pass - - -@pytest.mark.parametrize("pattern", ["jupyter server", "uvicorn main:app"]) -def test_restart_after_kill(sandbox: Sandbox, pattern: str): - client = make_client(sandbox) - assert wait_for_health(client) - - kill_process(sandbox, pattern) - - # Wait for systemd to restart the service(s) and health to come back - assert wait_for_health(client, 60, 500) - - execution = client.run_code("x = 1; x") - assert execution.text == "1" - client.close() diff --git a/tests/uv.lock b/tests/uv.lock deleted file mode 100644 index af6f090c..00000000 --- a/tests/uv.lock +++ /dev/null @@ -1,602 +0,0 @@ -version = 1 -revision = 3 -requires-python = ">=3.10" - -[[package]] -name = "anyio" -version = "4.15.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "idna" }, - { name = "typing-extensions", marker = "python_full_version < '3.15'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a9/d2/f4d173e22df740bc37b1db102b386ba719b66e95b0f0d751f556b387e6d2/anyio-4.15.1.tar.gz", hash = "sha256:9f28306018cbd6d329e64a36d58256edff76dd996fe423bc957326e578b82a94", size = 276966, upload-time = "2026-09-05T10:42:39.44Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl", hash = "sha256:6152fdbbf9a77fdec97731721bebf7c4c44f7c29b424b0065826173efc7ed101", size = 132079, upload-time = "2026-09-05T10:42:37.923Z" }, -] - -[[package]] -name = "attrs" -version = "26.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" }, -] - -[[package]] -name = "backports-asyncio-runner" -version = "1.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/ff/70dca7d7cb1cbc0edb2c6cc0c38b65cba36cccc491eca64cabd5fe7f8670/backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162", size = 69893, upload-time = "2025-07-02T02:27:15.685Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5", size = 12313, upload-time = "2025-07-02T02:27:14.263Z" }, -] - -[[package]] -name = "bracex" -version = "3.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ac/01/5f394b8bcd6e5b92f73130990960423bbb19711f906bd9fe9ea5557c667c/bracex-3.0.1.tar.gz", hash = "sha256:4e38e32392e4a4780fe15d644bfc7c8514057cfc3861e060b11814ce829c25e4", size = 44019, upload-time = "2026-07-20T13:43:00.335Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/8f/6f7273a7adb8d73fc8d21ede4376a3e475e52f98435c6007f69100dec8ca/bracex-3.0.1-py3-none-any.whl", hash = "sha256:6523ad83aeb5098a4ee597cff0f964442ff74e460bd3fafaffab6a013ff2288c", size = 11940, upload-time = "2026-07-20T13:42:59.268Z" }, -] - -[[package]] -name = "certifi" -version = "2026.7.22" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a3/c2/24167ea9858356b47a87a50d39908bfdb72ceeefe0041586e704e5376b3a/certifi-2026.7.22.tar.gz", hash = "sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55", size = 138112, upload-time = "2026-07-22T03:35:12.644Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl", hash = "sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775", size = 136983, upload-time = "2026-07-22T03:35:11.276Z" }, -] - -[[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, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "connectrpc" -version = "0.11.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "protobuf-py" }, - { name = "pyqwest" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8b/b5/63e14ab9d4d4cc58818562db4120a35fa7454e3035633da41bdc6b712abd/connectrpc-0.11.1.tar.gz", hash = "sha256:18277f7838847b4271ca38d40c7d2387b5a2ea6a29f240689c19e1ec84aaff66", size = 46222, upload-time = "2026-07-15T06:33:31.601Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/ac/aa647675812cd075f2cb9acb00d62f4f2cbcbc6736049a62342b7371ce5b/connectrpc-0.11.1-py3-none-any.whl", hash = "sha256:8a52e2e92a485fa9681c1101a79a5ebeb31807e3ea3d5aabd41f484a6398bc7b", size = 64991, upload-time = "2026-07-15T06:33:29.396Z" }, -] - -[[package]] -name = "dockerfile-parse" -version = "2.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/92/df/929ee0b5d2c8bd8d713c45e71b94ab57c7e11e322130724d54f469b2cd48/dockerfile-parse-2.0.1.tar.gz", hash = "sha256:3184ccdc513221983e503ac00e1aa504a2aa8f84e5de673c46b0b6eee99ec7bc", size = 24556, upload-time = "2023-07-18T13:36:07.897Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/6c/79cd5bc1b880d8c1a9a5550aa8dacd57353fa3bb2457227e1fb47383eb49/dockerfile_parse-2.0.1-py2.py3-none-any.whl", hash = "sha256:bdffd126d2eb26acf1066acb54cb2e336682e1d72b974a40894fac76a4df17f6", size = 14845, upload-time = "2023-07-18T13:36:06.052Z" }, -] - -[[package]] -name = "e2b" -version = "2.53.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "attrs" }, - { name = "connectrpc" }, - { name = "dockerfile-parse" }, - { name = "h2" }, - { name = "httpx" }, - { name = "packaging" }, - { name = "protobuf-py" }, - { name = "pyqwest" }, - { name = "python-dateutil" }, - { name = "rich" }, - { name = "typing-extensions" }, - { name = "wcmatch" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ff/84/a5798cbcd7e8a3d4d4b913b9caebd7ffcfd07f92e7ddef36c6972ce21f9c/e2b-2.53.1.tar.gz", hash = "sha256:c58fce7de1104f82b5402d1ec347b28535bfe34f5461ad677a0a752303f8d24b", size = 238284, upload-time = "2026-10-06T20:17:48.483Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/71/25fe260524bf9a7754781099ae7e30321e298d92f116373ef2e5d9e6d689/e2b-2.53.1-py3-none-any.whl", hash = "sha256:12ee0324aef2b6f064fe9037db52ddc3fcc6bec0e9c2064766b5e4a2b7c46d51", size = 400012, upload-time = "2026-10-06T20:17:46.254Z" }, -] - -[[package]] -name = "e2b-code-interpreter-tests" -version = "0.0.0" -source = { virtual = "." } -dependencies = [ - { name = "e2b" }, - { name = "httpx" }, - { name = "pytest" }, - { name = "pytest-asyncio" }, - { name = "pytest-dotenv" }, - { name = "pytest-xdist" }, - { name = "python-dotenv" }, - { name = "ruff" }, -] - -[package.metadata] -requires-dist = [ - { name = "e2b", specifier = ">=2.32.0,<3" }, - { name = "httpx", specifier = ">=0.28.1,<1" }, - { name = "pytest", specifier = ">=9.0.3,<10" }, - { name = "pytest-asyncio", specifier = ">=1.3.0,<2" }, - { name = "pytest-dotenv", specifier = ">=0.5.2,<0.6" }, - { name = "pytest-xdist", specifier = ">=3.6.1,<4" }, - { name = "python-dotenv", specifier = ">=1.2.1,<2" }, - { name = "ruff", specifier = ">=0.11.12,<0.12" }, -] - -[[package]] -name = "exceptiongroup" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, -] - -[[package]] -name = "execnet" -version = "2.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bf/89/780e11f9588d9e7128a3f87788354c7946a9cbb1401ad38a48c4db9a4f07/execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd", size = 166622, upload-time = "2025-11-12T09:56:37.75Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec", size = 40708, upload-time = "2025-11-12T09:56:36.333Z" }, -] - -[[package]] -name = "h11" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, -] - -[[package]] -name = "h2" -version = "4.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "hpack" }, - { name = "hyperframe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e7/85/7c366e69d84c17bb778fe41419e1fbcce3033d5b7ce29bbffff0a98b859f/h2-4.4.1.tar.gz", hash = "sha256:4e866ffb1a869ae14dd9b5e6beb5c24a13da0495ad72b65925ded182521c1516", size = 2157281, upload-time = "2026-08-03T11:45:09.509Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/22/e85faf23bd72a92d1921e37d674ca56eb298a3c8be31fdecef0ff2b3aaac/h2-4.4.1-py3-none-any.whl", hash = "sha256:0e25f1462b23c9cb82d9eb02e28bc706dac2a68cb457c6a0d74d63c8a2a5d0e6", size = 62636, upload-time = "2026-08-03T11:44:59.164Z" }, -] - -[[package]] -name = "hpack" -version = "4.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/5b/fcabf6028144a8723726318b07a32c2f3314acdff6265743cf08a344b18e/hpack-4.2.0.tar.gz", hash = "sha256:0895cfa3b5531fc65fe439c05eb65144f123bf7a394fcaa56aa423548d8e45c0", size = 51300, upload-time = "2026-06-23T18:34:46.667Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl", hash = "sha256:858ac0b02280fa582b5080d68db0899c62a80375e0e5413a74970c5e518b6986", size = 34246, upload-time = "2026-06-23T18:34:45.472Z" }, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, -] - -[[package]] -name = "hyperframe" -version = "6.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/02/e7/94f8232d4a74cc99514c13a9f995811485a6903d48e5d952771ef6322e30/hyperframe-6.1.0.tar.gz", hash = "sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08", size = 26566, upload-time = "2025-01-22T21:41:49.302Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5", size = 13007, upload-time = "2025-01-22T21:41:47.295Z" }, -] - -[[package]] -name = "idna" -version = "3.20" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f5/08/8eea9d4b8302028f3abb2c0813953f7aec26d33b7a8960ed760e65ff29fa/idna-3.20.tar.gz", hash = "sha256:a7db850025b95ded1eae8a46181a1a6c56c92c96f0e2b005d9ff8dc0210cab44", size = 216463, upload-time = "2026-09-17T14:11:04.752Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl", hash = "sha256:ab7ae7122974553370f0bdb919e1a960b2cd1bc1ef0276416d896db81c14582c", size = 69583, upload-time = "2026-09-17T14:11:03.168Z" }, -] - -[[package]] -name = "iniconfig" -version = "2.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/e1/2069291243c926a2ff1cd706c7f3eeb9b62144bf60f77c9fb9ff2fb26bd3/iniconfig-2.3.1.tar.gz", hash = "sha256:67f4b9c50da0dedf52af349e7749a80a9057a5031199791b906c3bb3ae878960", size = 21209, upload-time = "2026-10-06T22:48:38.076Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/56/43/4ca9e49d27a1fcf6bece6f6aec0ea46bb9112489b93d4b688fb415457bdb/iniconfig-2.3.1-py3-none-any.whl", hash = "sha256:9121e2c1fdb355232495be3194c8dfe87ccc2d5dee45947b78e68f499790d7a7", size = 7552, upload-time = "2026-10-06T22:48:36.959Z" }, -] - -[[package]] -name = "markdown-it-py" -version = "4.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, -] - -[[package]] -name = "opentelemetry-api" -version = "1.45.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2e/02/6e0ae9cc61bd3169d401077b507b3ebc344745171e1051ab430be012dcd9/opentelemetry_api-1.45.1.tar.gz", hash = "sha256:aa38ed19bcc084ba42782a73255b3582283eced7ad6dddbd6695189e69adfb75", size = 72804, upload-time = "2026-10-06T17:32:58.133Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/41/f7dcf80b81ee8e71c1a2b59f14208bc723edbd89ed027a73b175abf6348e/opentelemetry_api-1.45.1-py3-none-any.whl", hash = "sha256:b31553efa588ae44bc306f863c785c5333a9ecc091248c6ee68b4b6c87fdedfb", size = 60256, upload-time = "2026-10-06T17:32:33.506Z" }, -] - -[[package]] -name = "packaging" -version = "26.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", size = 313412, upload-time = "2026-08-04T18:15:28.737Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" }, -] - -[[package]] -name = "pluggy" -version = "1.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, -] - -[[package]] -name = "protobuf-py" -version = "0.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "protobuf-py-ext", marker = "(platform_machine == 'arm64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'AMD64' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'ARM64' and platform_python_implementation == 'CPython' and sys_platform == 'win32')" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/72/ed/02fd902d9c51b7ff53dfc9a745eb11490722edfd30073af889e171f07b8e/protobuf_py-0.1.1.tar.gz", hash = "sha256:6bd08ac4d8f1661965bbe2685429d79043704cdd1ee720a7a89617331742240b", size = 133525, upload-time = "2026-06-24T19:02:15.271Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/00/1b3775aca1c70e3007e06ef5996f6bb9b3a32341eb0cce3ffb6effad8dec/protobuf_py-0.1.1-py3-none-any.whl", hash = "sha256:efc4f50f275ed6dae10a1f30bb81ad1a75368557b3ff22a532b7a472050368f1", size = 181656, upload-time = "2026-06-24T19:01:29.556Z" }, -] - -[[package]] -name = "protobuf-py-ext" -version = "0.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2f/05/6dc9ccff1e8159eb9a144e6d3c4acfd2211cd4fcd20c34fe9155d17d6a7f/protobuf_py_ext-0.1.1.tar.gz", hash = "sha256:e85bfdfdb3ed50634db8ccc7429dd9286520109489c735463971a418707b4fef", size = 31912, upload-time = "2026-06-24T19:02:16.321Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/19/70/2b5d62a60a2e0d88ecde1ae98db3132bcd2672fb39c8d581b82b34ac0bd8/protobuf_py_ext-0.1.1-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:310039e03cb15181781a0b78017419f6d4ee302e988c3c70b87f1facdf05532d", size = 306008, upload-time = "2026-06-24T19:01:31.399Z" }, - { url = "https://files.pythonhosted.org/packages/2d/d6/73c06bb4cac2e04c0adc154965fe8b6520224bd737fd7e73bba405056321/protobuf_py_ext-0.1.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89ec8348d1ba045f79b2fedd14e40cca36f2a41b52f2c4fdf55a60c58add2353", size = 314769, upload-time = "2026-06-24T19:01:32.89Z" }, - { url = "https://files.pythonhosted.org/packages/18/c5/e4e6bc6096b66d1c82639a1b501147f16ee65d32567304b987d002e2c666/protobuf_py_ext-0.1.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:182798e4861aba72d05855bd06febe4926aa7265e6f444a1b8af5252beee4f7e", size = 328122, upload-time = "2026-06-24T19:01:34.394Z" }, - { url = "https://files.pythonhosted.org/packages/b0/4b/1d792a40d0f0a0f914f1dfa8bb5e9573ca0ecd5fe5cecf80d77193212abd/protobuf_py_ext-0.1.1-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9eb25c3a329c0551cc86b209a5e5d8ecb8d834b9924a3aa019377853a703b6d3", size = 492338, upload-time = "2026-06-24T19:01:36.103Z" }, - { url = "https://files.pythonhosted.org/packages/52/51/5ad329223c905e5c530cae38ae24cde3584d8ab7e09457f2a01afce80e60/protobuf_py_ext-0.1.1-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:aaecbde82bef10c7c40578cbb61b7a19896bf7fa450972050a3bb302acb7d5d6", size = 541578, upload-time = "2026-06-24T19:01:37.481Z" }, - { url = "https://files.pythonhosted.org/packages/ed/c7/01bd8a8bfe2df4b07aafac12ccfb7b7ebe2303f65296a9e02fcafa28ff3e/protobuf_py_ext-0.1.1-cp310-abi3-win_amd64.whl", hash = "sha256:6b0c615c48e95acc53cf33e9310eeaff8b30d2d7555bf93e7bca8fb4f40e9a5c", size = 251319, upload-time = "2026-06-24T19:01:38.946Z" }, - { url = "https://files.pythonhosted.org/packages/24/dc/914065538b5db54b6a920b5af38c1ef142252ea1eea711820435fa259fac/protobuf_py_ext-0.1.1-cp310-abi3-win_arm64.whl", hash = "sha256:72956cd0af5dee24b41c6f5ba5e42622d17e6d555002b5efc1634e27a1446de2", size = 241635, upload-time = "2026-06-24T19:01:40.301Z" }, - { url = "https://files.pythonhosted.org/packages/13/a5/0b5d73cab815fd50615cb87a02e04e8332f9e27380c890aba1459cf7e919/protobuf_py_ext-0.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c6f0cd58620f415a3534d195358338f4999a774e12510f91c592b38d13d37388", size = 304903, upload-time = "2026-06-24T19:01:41.796Z" }, - { url = "https://files.pythonhosted.org/packages/37/a9/14c120b9ac36a0e11bb05e482fa6ae322de583a8e1068e4859035c289947/protobuf_py_ext-0.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21572764f625d829604fc4d83635f533f35775f11c6da142345b3f3c8d64bd09", size = 316148, upload-time = "2026-06-24T19:01:43.247Z" }, - { url = "https://files.pythonhosted.org/packages/35/54/7c00a1a9783c3ba74f6b2f5d2f049f09037bbd489c465c09a34f32fb611b/protobuf_py_ext-0.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7f14f00c2678bfbe7ad46f057b9f9938c1677bcf39e405e163e272c6f9814b8", size = 326458, upload-time = "2026-06-24T19:01:44.655Z" }, - { url = "https://files.pythonhosted.org/packages/0d/0e/81fa50c0d6c4d664e5be6d0a3c4f2c7edfef87ab12d0bac764abca1f2955/protobuf_py_ext-0.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1610865622e2e27568277ca63d8d2d23dcc55eaa767398865c21539ddf4ce24d", size = 493596, upload-time = "2026-06-24T19:01:46.344Z" }, - { url = "https://files.pythonhosted.org/packages/56/19/3183cf6e4de62846c20549654a1d573dae51ca06aaf7fed06accdfab74f6/protobuf_py_ext-0.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8995efba9476e1ea18ef9873306871dba697308994bc2766558fec3387acc3de", size = 539656, upload-time = "2026-06-24T19:01:48.21Z" }, - { url = "https://files.pythonhosted.org/packages/a4/6c/09841f3dbe7c3d4b3f2779f8f2832ac23fb96ac8ab71674e91af732cf9ff/protobuf_py_ext-0.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ba61d49dace8f874361583030a7c48139b42eb37c9ffbb1e7e8a227a51576f44", size = 305017, upload-time = "2026-06-24T19:01:49.84Z" }, - { url = "https://files.pythonhosted.org/packages/52/43/e450b5e202f6715274acc9acd9f9769908cbdeab861a53c798fcbd467d35/protobuf_py_ext-0.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a9c2f026096ca4c595c89a297067ef371e241d3ff8e1f6d7c779aa8419cdca7", size = 316215, upload-time = "2026-06-24T19:01:51.249Z" }, - { url = "https://files.pythonhosted.org/packages/97/5c/23e79b35f1b5755b9bdc0c0c9b8cd8abababaef1a1639608d8a96bb61a9d/protobuf_py_ext-0.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf78707a040b9294e5e1ec4a1875f0046acfe52e92150cea27de4e9fc9db39bb", size = 326419, upload-time = "2026-06-24T19:01:52.93Z" }, - { url = "https://files.pythonhosted.org/packages/e8/de/5493de0ec12920a3b1dd72608ce0c1e8cdb7e0eb9e87accaecc5216df29e/protobuf_py_ext-0.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ae4373845cbb85bdade3ef5368cc2f4b5f80bf173383afc1ab063f95644e5599", size = 493734, upload-time = "2026-06-24T19:01:54.301Z" }, - { url = "https://files.pythonhosted.org/packages/98/89/31da55b414e6332aad11d858e9a86bd36fbb324f52fa3fc6d8f1c57840a9/protobuf_py_ext-0.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2a4cc478eef7a2acc1daaebcde479a3ac2396d47e6bdc7e776ca4c4147ba8b4c", size = 539703, upload-time = "2026-06-24T19:01:55.707Z" }, - { url = "https://files.pythonhosted.org/packages/1c/71/39f231838ef06476d46ac40dd814894277a732a3688c0a0c994850b3b62f/protobuf_py_ext-0.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:359dccdc1c3eafed2a913c570bb082b8df848a1d27d548ce8385f246a7d68be2", size = 302145, upload-time = "2026-06-24T19:01:57.116Z" }, - { url = "https://files.pythonhosted.org/packages/87/f1/01c81ff5f420600366a0e6a613ce2af20834534d2b3d7523f4f3b4ddb54f/protobuf_py_ext-0.1.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91c38b4a10a306366443273ee03ca554537a0965bf05b7ada8e7dbdee04cc93e", size = 314541, upload-time = "2026-06-24T19:01:58.745Z" }, - { url = "https://files.pythonhosted.org/packages/86/d8/1cbf5a0298ceddc0cdbb28bf1ecaf8bd3cff54ed4ced6a1392d5226172fc/protobuf_py_ext-0.1.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79eee3bcbb289d6ea114eb8fe3a1469c5b59bf53e207238469f567d9c53ba56f", size = 325092, upload-time = "2026-06-24T19:02:00.382Z" }, - { url = "https://files.pythonhosted.org/packages/af/23/8b1694616044cbfec2d18d4c6fffb03e05089c8bdb5970c6bafd60cc7fd5/protobuf_py_ext-0.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:10992141a8282a71ac3e3530d1a489efb27618d84000b9a47918cf70e5816d9b", size = 491684, upload-time = "2026-06-24T19:02:01.862Z" }, - { url = "https://files.pythonhosted.org/packages/49/d8/99997a7a6cf6989c944d9183c5deb6a045c27460add0316c7b34763891b3/protobuf_py_ext-0.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4411ffe0e06a774b83c5c71c546ce097640a25f596c45f95f53d3e3148e3f22d", size = 538048, upload-time = "2026-06-24T19:02:03.362Z" }, - { url = "https://files.pythonhosted.org/packages/15/3c/9e99ecbb68e1d5b46016d821eb1cbba9a91e6b50e71e75faf0c1e6189f0d/protobuf_py_ext-0.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:55a17d80ea419501ff221a6627523f38a431bb33e6aa3de81ae3a7f271c49c75", size = 296337, upload-time = "2026-06-24T19:02:04.787Z" }, - { url = "https://files.pythonhosted.org/packages/af/f2/305338a28225fb54b28d6c3f5948109b9088b329a2b6f77ca610c2bdcd34/protobuf_py_ext-0.1.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dbb518b5638403ceaa08ac4fc7dac626f45ed9b856b3517de3906cf3de4d632", size = 308961, upload-time = "2026-06-24T19:02:06.185Z" }, - { url = "https://files.pythonhosted.org/packages/60/f9/416103c93677ff2ea407704ea64fa6de9e700dc030c48360a182d91ce373/protobuf_py_ext-0.1.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a4adc65ab6a5e4885c67fc808bcacb83d755d05b566d312a0e10c2a873f2ad4", size = 321895, upload-time = "2026-06-24T19:02:07.714Z" }, - { url = "https://files.pythonhosted.org/packages/5a/83/eb3e81bb2f83834b7deff4cee2d56eeb1adcbc847492a56b7f910ab257db/protobuf_py_ext-0.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e97f45c49676efacfb8e95bfcb1a002bc337e618a6780be1e55df2ba5ebd2f1e", size = 486091, upload-time = "2026-06-24T19:02:09.243Z" }, - { url = "https://files.pythonhosted.org/packages/99/96/bd88fca38556b3105e4dd41d6a176e31dcc583fe979e830aeedd2f8c20ee/protobuf_py_ext-0.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:53a6b3590f6aa7f97b8ed60f62fef9b096babfeae82f7283fd3a4c405827d4f8", size = 534582, upload-time = "2026-06-24T19:02:11.227Z" }, -] - -[[package]] -name = "pygments" -version = "2.21.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/2e/ced460408999b33da6b31b0021b0f37d329e202d4169aeb164493778f25b/pygments-2.21.0.tar.gz", hash = "sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c", size = 5005329, upload-time = "2026-08-17T08:02:48.824Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl", hash = "sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9", size = 1250147, upload-time = "2026-08-17T08:02:44.912Z" }, -] - -[[package]] -name = "pyqwest" -version = "0.10.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "opentelemetry-api" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/07/ee/0ff9facfa9e7a4f6df2a770d4eaf1ad0f74165da7e8c28e888461f07604c/pyqwest-0.10.0.tar.gz", hash = "sha256:6c1a693be17d57d2c2eca4085e32c2809c53090c16719a907c90ebcf1f40dc01", size = 482248, upload-time = "2026-08-21T06:09:20.656Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/43/ee/b1a28f57c689606cfd065d8a553841150f7daaa91d20e58dcc2c5ea191f8/pyqwest-0.10.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:aa492d5777dd145a60795ed95d9d4707a3cd1091fdcdfc93a82ac7fdc43ebacd", size = 5261059, upload-time = "2026-08-21T06:08:04.999Z" }, - { url = "https://files.pythonhosted.org/packages/dc/13/9c5046cfd6ef705bde0b620ba8a794335bcabc0839342a2a647f2427b27e/pyqwest-0.10.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:59f3f16628e518c674102e7b5fcff2101bba6abb4f6737ec5fade9b9278e6a53", size = 5134207, upload-time = "2026-08-21T06:08:06.955Z" }, - { url = "https://files.pythonhosted.org/packages/93/7d/50021dd88d82d6966ab1c27593ceaee9d1ed62fbe597c40e8dc187cfa5fd/pyqwest-0.10.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6e7db305a8318b1f3218053e87501f8f245ca8bd63e948e0282d04bf0883470", size = 5640730, upload-time = "2026-08-21T06:08:09.135Z" }, - { url = "https://files.pythonhosted.org/packages/ff/3f/5bf6c32e9e701837a8c47ce6e3ad38978cfec8eb7bc6596181e5f9e1eaeb/pyqwest-0.10.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5c757cfac5f53c8671dcb4850d5fc4c4339ea3e90636331c9318f8e3ddabc06", size = 5561462, upload-time = "2026-08-21T06:08:10.836Z" }, - { url = "https://files.pythonhosted.org/packages/5f/61/ca9ba5721461b7ce5cfaac373ab3a1723ddcc434af7430f8bd628da6e623/pyqwest-0.10.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:234b3f71e3f314d997c203d8cf829b7117edd041153f9c277d0060ab90134148", size = 5801847, upload-time = "2026-08-21T06:08:12.502Z" }, - { url = "https://files.pythonhosted.org/packages/d2/44/95593919b996a417093f598d887822b9b899e8d025588c9bfaf8c60dd812/pyqwest-0.10.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5637256a0dac0ef57e0eaa02b032014965e4a4c995e1deca1b1b97e6d1765f78", size = 5978692, upload-time = "2026-08-21T06:08:14.383Z" }, - { url = "https://files.pythonhosted.org/packages/a5/b9/b2821ce5188457168ebb25d5ff65b1ca1bf27bc6b4a33df4bcc2357e625c/pyqwest-0.10.0-cp310-abi3-win_amd64.whl", hash = "sha256:7ea761937acf3a00d1a7e70e982949d18946e5471d1419266ab3a78bbfa19759", size = 4876627, upload-time = "2026-08-21T06:08:16.084Z" }, - { url = "https://files.pythonhosted.org/packages/86/b4/16ccef1c203fa258ce46a86aefc1a79c13b5f0b8d49627347d90eef25efd/pyqwest-0.10.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a21f1f15252a8303623b4f17b9c6de595ace11b3ade07f2adb6d07121e8191aa", size = 5274815, upload-time = "2026-08-21T06:08:17.777Z" }, - { url = "https://files.pythonhosted.org/packages/5f/61/6a87f84f571441ea43279587d4bfcad4543505918ae2b83a1ebdcfa98be5/pyqwest-0.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:eb472c6e5d6833ebfec79db310e426eb17b01ac64c0e2c251bd9192c0d2ee0c5", size = 5123656, upload-time = "2026-08-21T06:08:19.501Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f2/ab69e581cf9b798b0e169f7b27fd3f8b6f9f1631bd4d3b6e22e5abaf8d8b/pyqwest-0.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83578e24cccd5e0dc04d60a0af7bfb43325b5f22d03ff74ff79ed0ecf553b50d", size = 5641253, upload-time = "2026-08-21T06:08:21.627Z" }, - { url = "https://files.pythonhosted.org/packages/9f/dd/f1a62eebf8321ace506bd94551a01431f6a45b882225455eae3ea6e8c6d1/pyqwest-0.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bb511c434f79c641efb5573e5795e56dc972252f4b96e52a9636d4ece5231a4", size = 5567341, upload-time = "2026-08-21T06:08:23.346Z" }, - { url = "https://files.pythonhosted.org/packages/4c/48/51d767691973e046887f5e6d96e32142fe296823b163ccba732233a6ef72/pyqwest-0.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1aaccd8a9db9430b2aedb5bad8ead80742cbc056b85c229516c70dc80539f906", size = 5803874, upload-time = "2026-08-21T06:08:25.096Z" }, - { url = "https://files.pythonhosted.org/packages/58/0a/d2834ccc6e59ad110718895cc65ff2a68aa6e010f0ba8fbe42a57ea33c21/pyqwest-0.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:73d9eb438ab4a957a1ce0619d3af8c1c1126bfb9181033b123d792fcf4224531", size = 5981518, upload-time = "2026-08-21T06:08:27.594Z" }, - { url = "https://files.pythonhosted.org/packages/75/f3/274b4c268e9a55fbdb1b3637ac50b5bf42cd3a85d1cfbdc15c602a7b0d9c/pyqwest-0.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:317a74d633abe3bc5bccabf479e069c515dab9e6a755274b0ccb1d8a5bbfede3", size = 4870638, upload-time = "2026-08-21T06:08:29.421Z" }, - { url = "https://files.pythonhosted.org/packages/8d/3d/8b1092f25159bf61a9470ebd35438c669b91ef553a7ee205bdec8006107b/pyqwest-0.10.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3978e794b9cfd8eaa500fb5d7aee63bc6172c605efa0abc1f62d85485bc049e1", size = 5273599, upload-time = "2026-08-21T06:08:31.107Z" }, - { url = "https://files.pythonhosted.org/packages/75/10/54a9786123942b124c2afb9562b74e158afec7be40ef0caa0d37f615d379/pyqwest-0.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:715991fd4f04862cd7a9d7452daabcdbd74dff4dff55eb20c22d60382dc2a4ed", size = 5122920, upload-time = "2026-08-21T06:08:33.025Z" }, - { url = "https://files.pythonhosted.org/packages/a2/5b/6a6bd76f91e068b9a619f62aef9fe5ef201f859ddbb6b0a11ad3875ecdda/pyqwest-0.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c04798bed79c1dfa0e5b0e30fb137124311083490d44d6dfbe068d3dd254349e", size = 5639577, upload-time = "2026-08-21T06:08:34.896Z" }, - { url = "https://files.pythonhosted.org/packages/68/28/12277a24a8dd74b0a7f124c624d9ed58eccb41e2087ff1087a14d348c778/pyqwest-0.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35b472877e73dd63fed089c2bc8fa198407f005c8c19e0a93f025ebefde01a81", size = 5565835, upload-time = "2026-08-21T06:08:36.567Z" }, - { url = "https://files.pythonhosted.org/packages/9e/b6/b7da4a3f1fe43600154ae75e91ba7969024d886d60077dd3a1ba8e66d170/pyqwest-0.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:564ec360b7848b35e009038ffbca00466305a9708ab21829477f64aa8cad4c64", size = 5803078, upload-time = "2026-08-21T06:08:38.362Z" }, - { url = "https://files.pythonhosted.org/packages/0c/6f/0c9ba210f49f232289afaa8f06369c5f135ac786e1ca0cb22243b7f1fe2c/pyqwest-0.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b5c80e88a5967c1cadb3237c450f91a84a3683f8838c8dca96f09fee3612e762", size = 5980431, upload-time = "2026-08-21T06:08:39.967Z" }, - { url = "https://files.pythonhosted.org/packages/9b/f5/306eeed41a3cd3100247e6e442f4345277b70f1d24efe1641181b14839cd/pyqwest-0.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:dc3d80b402fb59dbe015e25993ac8147456fb231a4c949f92a89f31315ad50f9", size = 4870198, upload-time = "2026-08-21T06:08:41.687Z" }, - { url = "https://files.pythonhosted.org/packages/64/18/0086a408e7cbf39dab18fa5b7e42c969a98382da5a4e6debe40f05acc6a1/pyqwest-0.10.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:23a28beb55fa6d975949bffae4adfb69378f3229bb5cbd71231e95bf66f5b26c", size = 5274542, upload-time = "2026-08-21T06:08:43.323Z" }, - { url = "https://files.pythonhosted.org/packages/0c/7b/e1b9aaaf7596e4faaa53cefc2efaca4e3cde721e308e6385e366361cfdcc/pyqwest-0.10.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e4415ae40b8eedb1713dab14d7f9fecc3f79d26f3206c561087b88b99d5ce24b", size = 5127922, upload-time = "2026-08-21T06:08:45.116Z" }, - { url = "https://files.pythonhosted.org/packages/75/cd/e6d68bb1de5dd26100fcfc878cbd67c402a928774edf1e8ae304c5a84f5b/pyqwest-0.10.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14b875d2273212d7fa8e4b755d8d736ffd226b1c707a9c0017dfdc8393a96eca", size = 5645856, upload-time = "2026-08-21T06:08:47.055Z" }, - { url = "https://files.pythonhosted.org/packages/f7/48/8c9f9f0467c41f6a563146d57a52f8f6d60c0cb09d0fd3ef88ad5a1c442f/pyqwest-0.10.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5071491e416ea54e3b95bf9ffbed0bd065b093cb96e10a75c3d8f2cbe3c9823", size = 5569831, upload-time = "2026-08-21T06:08:48.78Z" }, - { url = "https://files.pythonhosted.org/packages/16/ac/c85ab70c6c72078d49a82da76b820e46aaf95a3f6fe271dac955ac195d21/pyqwest-0.10.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b68b5e68d513a4c63a072f8f40e38015160cf90bfbf7e8ef7c3935ca87e9e022", size = 5806735, upload-time = "2026-08-21T06:08:50.652Z" }, - { url = "https://files.pythonhosted.org/packages/66/db/ad7375b22fb2d0807431dcc9bc2aaf840e374c298cd15071024d5f6dd6d1/pyqwest-0.10.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c48910d27820b9c46fcd001b0fe514a3cf47d4784f59512dcdb8c91c395f82e4", size = 5984786, upload-time = "2026-08-21T06:08:52.377Z" }, - { url = "https://files.pythonhosted.org/packages/17/88/c449a772afe129683fd7acc657cbc7c69bec085dc75b6e8710a50fbb44e7/pyqwest-0.10.0-cp314-cp314-win_amd64.whl", hash = "sha256:d03ba2cd17948b623a6210981d342eb122546d8a8e910ec77511aff4b1acdd00", size = 4872288, upload-time = "2026-08-21T06:08:54.101Z" }, - { url = "https://files.pythonhosted.org/packages/3d/f8/439ffc0ee12cd7d9b57ac07ccea78ad3ba66b0d6817d429dd661d73308c4/pyqwest-0.10.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:07a0eb595f4096232c2d22549b6e4612c1ecada7934e46462c2c37ce14a89cfb", size = 5256823, upload-time = "2026-08-21T06:08:55.681Z" }, - { url = "https://files.pythonhosted.org/packages/df/2b/72ecd27d104d2b4284710194cce796d607674966c3ea66436768e812a66a/pyqwest-0.10.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:26401baf7dafc71c8d12d2e8389519d141e6f7c14094d0dd4cf9ec1d3b5555bd", size = 5112624, upload-time = "2026-08-21T06:08:57.366Z" }, - { url = "https://files.pythonhosted.org/packages/a4/24/0fb89c3f7d5a0410fcb7560588b4c741ef24b19195c307d4263f04e75c2b/pyqwest-0.10.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5e3c436e041d8873ce5bb0fdcf9f9e86f5604e8f0ef9e03149efebd8cb474f6", size = 5631844, upload-time = "2026-08-21T06:08:59.165Z" }, - { url = "https://files.pythonhosted.org/packages/4c/4f/921d14754a186f0143ad62b50108dd808328e347e98e9dafab3897eeb405/pyqwest-0.10.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09364115761579eabfc79d1e954cdb3ded508dac1903fac7285d4c6f058c683f", size = 5555869, upload-time = "2026-08-21T06:09:00.783Z" }, - { url = "https://files.pythonhosted.org/packages/b8/70/504780417319a626fe9549a7e6f9020a3d448eddf8a09617238a3426e90c/pyqwest-0.10.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:559674a98a8b1217e1830ecd41c9905bf2b60983c6b8017063dfac199f00727c", size = 5793738, upload-time = "2026-08-21T06:09:03.324Z" }, - { url = "https://files.pythonhosted.org/packages/45/f7/8d0a5b8a3289f4300dc9005ebde75d316f2371a2671617f942036337731a/pyqwest-0.10.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f399a696392fff3db3eef0a18ef65b8a3b8396d129193487d966b8eb11006376", size = 5972889, upload-time = "2026-08-21T06:09:05.2Z" }, - { url = "https://files.pythonhosted.org/packages/89/c4/f4c781e475c451cb5f4762a2f814a1750ef375b8db4db09bb2dcea03c4e5/pyqwest-0.10.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0f9163d6dd991bf1bf27308ba38ba021af660b15fffa47ebca98e41cf6f00309", size = 4858036, upload-time = "2026-08-21T06:09:06.926Z" }, - { url = "https://files.pythonhosted.org/packages/7a/6f/29f605665f33aab894db8daf11b3b64bdca015fb11135815c53a150191a6/pyqwest-0.10.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cfcc7ba0229baa17831582befb046ace167b368140dae022d0b89b8d586ba12c", size = 5264903, upload-time = "2026-08-21T06:09:09.183Z" }, - { url = "https://files.pythonhosted.org/packages/c8/c8/4ce4b40f21397a6482da910fae18b32c28dcdaddf3498aef2fe38597a9e0/pyqwest-0.10.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:eff9ccf427604d34c635954def07b6113d4754f968073eef2df40bdb80b05bf5", size = 5142291, upload-time = "2026-08-21T06:09:10.943Z" }, - { url = "https://files.pythonhosted.org/packages/41/34/7205db9cddc5a2286da459ca013af629e20f09498751c60093b952379add/pyqwest-0.10.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78662158093f9d5c742368f4dd9956aa595f44c6ac0860777c98853ddd5e1610", size = 5648118, upload-time = "2026-08-21T06:09:12.616Z" }, - { url = "https://files.pythonhosted.org/packages/1e/94/75c6cd5d01cf68c99c0cfd66b165dce3fd9d9fce97cd4973117cab68355d/pyqwest-0.10.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0879a3f0b37876372aa328b9fee956165db174c1ab72464146fe515f49399ddb", size = 5565620, upload-time = "2026-08-21T06:09:14.223Z" }, - { url = "https://files.pythonhosted.org/packages/7a/a6/20a910d2f096908cf25ec47fa84b35b1bbb1af63dc9713f53f38ed97802e/pyqwest-0.10.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:850b8de6ade09a60bdb2f969871a177c2c304b594b2034ba3f5962c7bea75551", size = 5809262, upload-time = "2026-08-21T06:09:15.897Z" }, - { url = "https://files.pythonhosted.org/packages/e4/f7/f92fe4004d93f08c5118e750feefdbc72a73438b7fd7083300728e999911/pyqwest-0.10.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:399802647ea646c6ac9b5460e541b7c209b7a13563c667b2690ded2060185f2e", size = 5985550, upload-time = "2026-08-21T06:09:17.579Z" }, - { url = "https://files.pythonhosted.org/packages/47/3e/2c896e54dbe3f1ba6e3bd10e9d412f422a2e33827ff591d59f67b13e0fa5/pyqwest-0.10.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c26f3de1feb5d066d7a66802a47407a93ba043696064ad80beda4a0a4bf10056", size = 4873529, upload-time = "2026-08-21T06:09:19.161Z" }, -] - -[[package]] -name = "pytest" -version = "9.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "iniconfig" }, - { name = "packaging" }, - { name = "pluggy" }, - { name = "pygments" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, -] - -[[package]] -name = "pytest-asyncio" -version = "1.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "backports-asyncio-runner", marker = "python_full_version < '3.11'" }, - { name = "pytest" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/43/7c/d36d04db312ecf4298932ef77e6e4a9e8ad017906e24e34f0b0c361a2473/pytest_asyncio-1.4.0.tar.gz", hash = "sha256:c6c0d2259945122819f171a32ecea2c349ead889ee28176caaf492143424be42", size = 58514, upload-time = "2026-05-26T09:56:04.083Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl", hash = "sha256:933ca923a23075a87fb7070c0ec272a6848489824d887c85c812670932835aa1", size = 16930, upload-time = "2026-05-26T09:56:02.576Z" }, -] - -[[package]] -name = "pytest-dotenv" -version = "0.5.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pytest" }, - { name = "python-dotenv" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/cd/b0/cafee9c627c1bae228eb07c9977f679b3a7cb111b488307ab9594ba9e4da/pytest-dotenv-0.5.2.tar.gz", hash = "sha256:2dc6c3ac6d8764c71c6d2804e902d0ff810fa19692e95fe138aefc9b1aa73732", size = 3782, upload-time = "2020-06-16T12:38:03.4Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/da/9da67c67b3d0963160e3d2cbc7c38b6fae342670cc8e6d5936644b2cf944/pytest_dotenv-0.5.2-py3-none-any.whl", hash = "sha256:40a2cece120a213898afaa5407673f6bd924b1fa7eafce6bda0e8abffe2f710f", size = 3993, upload-time = "2020-06-16T12:38:01.139Z" }, -] - -[[package]] -name = "pytest-xdist" -version = "3.8.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "execnet" }, - { name = "pytest" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/78/b4/439b179d1ff526791eb921115fca8e44e596a13efeda518b9d845a619450/pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1", size = 88069, upload-time = "2025-07-01T13:30:59.346Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88", size = 46396, upload-time = "2025-07-01T13:30:56.632Z" }, -] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, -] - -[[package]] -name = "python-dotenv" -version = "1.2.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/74/26/2fbeedb218a787a5eea551c7532cac4e009f83d689dd2faa0d0353473f86/python_dotenv-1.2.4.tar.gz", hash = "sha256:f0d53e69935a851c0dcc78f3ab7aaccd8cabef0b92382b576b824212902873c0", size = 60824, upload-time = "2026-10-01T05:36:10Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/60/d1/38f3a3405989a89ac18390803e70c6ad7c7760da4f9b83cbeca0c44a0c72/python_dotenv-1.2.4-py3-none-any.whl", hash = "sha256:42269a8a5b3fd54ffa6f3d84b18abed50064717576b4ecf03dc4a55d8aa04fdc", size = 23266, upload-time = "2026-10-01T05:36:08.633Z" }, -] - -[[package]] -name = "rich" -version = "15.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" }, -] - -[[package]] -name = "ruff" -version = "0.11.13" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ed/da/9c6f995903b4d9474b39da91d2d626659af3ff1eeb43e9ae7c119349dba6/ruff-0.11.13.tar.gz", hash = "sha256:26fa247dc68d1d4e72c179e08889a25ac0c7ba4d78aecfc835d49cbfd60bf514", size = 4282054, upload-time = "2025-06-05T21:00:15.721Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/ce/a11d381192966e0b4290842cc8d4fac7dc9214ddf627c11c1afff87da29b/ruff-0.11.13-py3-none-linux_armv6l.whl", hash = "sha256:4bdfbf1240533f40042ec00c9e09a3aade6f8c10b6414cf11b519488d2635d46", size = 10292516, upload-time = "2025-06-05T20:59:32.944Z" }, - { url = "https://files.pythonhosted.org/packages/78/db/87c3b59b0d4e753e40b6a3b4a2642dfd1dcaefbff121ddc64d6c8b47ba00/ruff-0.11.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:aef9c9ed1b5ca28bb15c7eac83b8670cf3b20b478195bd49c8d756ba0a36cf48", size = 11106083, upload-time = "2025-06-05T20:59:37.03Z" }, - { url = "https://files.pythonhosted.org/packages/77/79/d8cec175856ff810a19825d09ce700265f905c643c69f45d2b737e4a470a/ruff-0.11.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53b15a9dfdce029c842e9a5aebc3855e9ab7771395979ff85b7c1dedb53ddc2b", size = 10436024, upload-time = "2025-06-05T20:59:39.741Z" }, - { url = "https://files.pythonhosted.org/packages/8b/5b/f6d94f2980fa1ee854b41568368a2e1252681b9238ab2895e133d303538f/ruff-0.11.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab153241400789138d13f362c43f7edecc0edfffce2afa6a68434000ecd8f69a", size = 10646324, upload-time = "2025-06-05T20:59:42.185Z" }, - { url = "https://files.pythonhosted.org/packages/6c/9c/b4c2acf24ea4426016d511dfdc787f4ce1ceb835f3c5fbdbcb32b1c63bda/ruff-0.11.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c51f93029d54a910d3d24f7dd0bb909e31b6cd989a5e4ac513f4eb41629f0dc", size = 10174416, upload-time = "2025-06-05T20:59:44.319Z" }, - { url = "https://files.pythonhosted.org/packages/f3/10/e2e62f77c65ede8cd032c2ca39c41f48feabedb6e282bfd6073d81bb671d/ruff-0.11.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1808b3ed53e1a777c2ef733aca9051dc9bf7c99b26ece15cb59a0320fbdbd629", size = 11724197, upload-time = "2025-06-05T20:59:46.935Z" }, - { url = "https://files.pythonhosted.org/packages/bb/f0/466fe8469b85c561e081d798c45f8a1d21e0b4a5ef795a1d7f1a9a9ec182/ruff-0.11.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d28ce58b5ecf0f43c1b71edffabe6ed7f245d5336b17805803312ec9bc665933", size = 12511615, upload-time = "2025-06-05T20:59:49.534Z" }, - { url = "https://files.pythonhosted.org/packages/17/0e/cefe778b46dbd0cbcb03a839946c8f80a06f7968eb298aa4d1a4293f3448/ruff-0.11.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55e4bc3a77842da33c16d55b32c6cac1ec5fb0fbec9c8c513bdce76c4f922165", size = 12117080, upload-time = "2025-06-05T20:59:51.654Z" }, - { url = "https://files.pythonhosted.org/packages/5d/2c/caaeda564cbe103bed145ea557cb86795b18651b0f6b3ff6a10e84e5a33f/ruff-0.11.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:633bf2c6f35678c56ec73189ba6fa19ff1c5e4807a78bf60ef487b9dd272cc71", size = 11326315, upload-time = "2025-06-05T20:59:54.469Z" }, - { url = "https://files.pythonhosted.org/packages/75/f0/782e7d681d660eda8c536962920c41309e6dd4ebcea9a2714ed5127d44bd/ruff-0.11.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ffbc82d70424b275b089166310448051afdc6e914fdab90e08df66c43bb5ca9", size = 11555640, upload-time = "2025-06-05T20:59:56.986Z" }, - { url = "https://files.pythonhosted.org/packages/5d/d4/3d580c616316c7f07fb3c99dbecfe01fbaea7b6fd9a82b801e72e5de742a/ruff-0.11.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4a9ddd3ec62a9a89578c85842b836e4ac832d4a2e0bfaad3b02243f930ceafcc", size = 10507364, upload-time = "2025-06-05T20:59:59.154Z" }, - { url = "https://files.pythonhosted.org/packages/5a/dc/195e6f17d7b3ea6b12dc4f3e9de575db7983db187c378d44606e5d503319/ruff-0.11.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d237a496e0778d719efb05058c64d28b757c77824e04ffe8796c7436e26712b7", size = 10141462, upload-time = "2025-06-05T21:00:01.481Z" }, - { url = "https://files.pythonhosted.org/packages/f4/8e/39a094af6967faa57ecdeacb91bedfb232474ff8c3d20f16a5514e6b3534/ruff-0.11.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:26816a218ca6ef02142343fd24c70f7cd8c5aa6c203bca284407adf675984432", size = 11121028, upload-time = "2025-06-05T21:00:04.06Z" }, - { url = "https://files.pythonhosted.org/packages/5a/c0/b0b508193b0e8a1654ec683ebab18d309861f8bd64e3a2f9648b80d392cb/ruff-0.11.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:51c3f95abd9331dc5b87c47ac7f376db5616041173826dfd556cfe3d4977f492", size = 11602992, upload-time = "2025-06-05T21:00:06.249Z" }, - { url = "https://files.pythonhosted.org/packages/7c/91/263e33ab93ab09ca06ce4f8f8547a858cc198072f873ebc9be7466790bae/ruff-0.11.13-py3-none-win32.whl", hash = "sha256:96c27935418e4e8e77a26bb05962817f28b8ef3843a6c6cc49d8783b5507f250", size = 10474944, upload-time = "2025-06-05T21:00:08.459Z" }, - { url = "https://files.pythonhosted.org/packages/46/f4/7c27734ac2073aae8efb0119cae6931b6fb48017adf048fdf85c19337afc/ruff-0.11.13-py3-none-win_amd64.whl", hash = "sha256:29c3189895a8a6a657b7af4e97d330c8a3afd2c9c8f46c81e2fc5a31866517e3", size = 11548669, upload-time = "2025-06-05T21:00:11.147Z" }, - { url = "https://files.pythonhosted.org/packages/ec/bf/b273dd11673fed8a6bd46032c0ea2a04b2ac9bfa9c628756a5856ba113b0/ruff-0.11.13-py3-none-win_arm64.whl", hash = "sha256:b4385285e9179d608ff1d2fb9922062663c658605819a6876d8beef0c30b7f3b", size = 10683928, upload-time = "2025-06-05T21:00:13.758Z" }, -] - -[[package]] -name = "six" -version = "1.17.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, -] - -[[package]] -name = "tomli" -version = "2.4.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/11/db3d5885d8528263d8adc260bb2d28ebf1270b96e98f0e0268d32b8d9900/tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30", size = 154704, upload-time = "2026-03-25T20:21:10.473Z" }, - { url = "https://files.pythonhosted.org/packages/6d/f7/675db52c7e46064a9aa928885a9b20f4124ecb9bc2e1ce74c9106648d202/tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a", size = 149454, upload-time = "2026-03-25T20:21:12.036Z" }, - { url = "https://files.pythonhosted.org/packages/61/71/81c50943cf953efa35bce7646caab3cf457a7d8c030b27cfb40d7235f9ee/tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076", size = 237561, upload-time = "2026-03-25T20:21:13.098Z" }, - { url = "https://files.pythonhosted.org/packages/48/c1/f41d9cb618acccca7df82aaf682f9b49013c9397212cb9f53219e3abac37/tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9", size = 243824, upload-time = "2026-03-25T20:21:14.569Z" }, - { url = "https://files.pythonhosted.org/packages/22/e4/5a816ecdd1f8ca51fb756ef684b90f2780afc52fc67f987e3c61d800a46d/tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c", size = 242227, upload-time = "2026-03-25T20:21:15.712Z" }, - { url = "https://files.pythonhosted.org/packages/6b/49/2b2a0ef529aa6eec245d25f0c703e020a73955ad7edf73e7f54ddc608aa5/tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc", size = 247859, upload-time = "2026-03-25T20:21:17.001Z" }, - { url = "https://files.pythonhosted.org/packages/83/bd/6c1a630eaca337e1e78c5903104f831bda934c426f9231429396ce3c3467/tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049", size = 97204, upload-time = "2026-03-25T20:21:18.079Z" }, - { url = "https://files.pythonhosted.org/packages/42/59/71461df1a885647e10b6bb7802d0b8e66480c61f3f43079e0dcd315b3954/tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e", size = 108084, upload-time = "2026-03-25T20:21:18.978Z" }, - { url = "https://files.pythonhosted.org/packages/b8/83/dceca96142499c069475b790e7913b1044c1a4337e700751f48ed723f883/tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece", size = 95285, upload-time = "2026-03-25T20:21:20.309Z" }, - { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload-time = "2026-03-25T20:21:21.626Z" }, - { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload-time = "2026-03-25T20:21:23.002Z" }, - { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload-time = "2026-03-25T20:21:24.04Z" }, - { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341, upload-time = "2026-03-25T20:21:25.177Z" }, - { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159, upload-time = "2026-03-25T20:21:26.364Z" }, - { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290, upload-time = "2026-03-25T20:21:27.46Z" }, - { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141, upload-time = "2026-03-25T20:21:28.492Z" }, - { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847, upload-time = "2026-03-25T20:21:29.386Z" }, - { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088, upload-time = "2026-03-25T20:21:30.677Z" }, - { url = "https://files.pythonhosted.org/packages/07/06/b823a7e818c756d9a7123ba2cda7d07bc2dd32835648d1a7b7b7a05d848d/tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54", size = 155866, upload-time = "2026-03-25T20:21:31.65Z" }, - { url = "https://files.pythonhosted.org/packages/14/6f/12645cf7f08e1a20c7eb8c297c6f11d31c1b50f316a7e7e1e1de6e2e7b7e/tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a", size = 149887, upload-time = "2026-03-25T20:21:33.028Z" }, - { url = "https://files.pythonhosted.org/packages/5c/e0/90637574e5e7212c09099c67ad349b04ec4d6020324539297b634a0192b0/tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897", size = 243704, upload-time = "2026-03-25T20:21:34.51Z" }, - { url = "https://files.pythonhosted.org/packages/10/8f/d3ddb16c5a4befdf31a23307f72828686ab2096f068eaf56631e136c1fdd/tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f", size = 251628, upload-time = "2026-03-25T20:21:36.012Z" }, - { url = "https://files.pythonhosted.org/packages/e3/f1/dbeeb9116715abee2485bf0a12d07a8f31af94d71608c171c45f64c0469d/tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d", size = 247180, upload-time = "2026-03-25T20:21:37.136Z" }, - { url = "https://files.pythonhosted.org/packages/d3/74/16336ffd19ed4da28a70959f92f506233bd7cfc2332b20bdb01591e8b1d1/tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5", size = 251674, upload-time = "2026-03-25T20:21:38.298Z" }, - { url = "https://files.pythonhosted.org/packages/16/f9/229fa3434c590ddf6c0aa9af64d3af4b752540686cace29e6281e3458469/tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd", size = 97976, upload-time = "2026-03-25T20:21:39.316Z" }, - { url = "https://files.pythonhosted.org/packages/6a/1e/71dfd96bcc1c775420cb8befe7a9d35f2e5b1309798f009dca17b7708c1e/tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36", size = 108755, upload-time = "2026-03-25T20:21:40.248Z" }, - { url = "https://files.pythonhosted.org/packages/83/7a/d34f422a021d62420b78f5c538e5b102f62bea616d1d75a13f0a88acb04a/tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd", size = 95265, upload-time = "2026-03-25T20:21:41.219Z" }, - { url = "https://files.pythonhosted.org/packages/3c/fb/9a5c8d27dbab540869f7c1f8eb0abb3244189ce780ba9cd73f3770662072/tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf", size = 155726, upload-time = "2026-03-25T20:21:42.23Z" }, - { url = "https://files.pythonhosted.org/packages/62/05/d2f816630cc771ad836af54f5001f47a6f611d2d39535364f148b6a92d6b/tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac", size = 149859, upload-time = "2026-03-25T20:21:43.386Z" }, - { url = "https://files.pythonhosted.org/packages/ce/48/66341bdb858ad9bd0ceab5a86f90eddab127cf8b046418009f2125630ecb/tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662", size = 244713, upload-time = "2026-03-25T20:21:44.474Z" }, - { url = "https://files.pythonhosted.org/packages/df/6d/c5fad00d82b3c7a3ab6189bd4b10e60466f22cfe8a08a9394185c8a8111c/tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853", size = 252084, upload-time = "2026-03-25T20:21:45.62Z" }, - { url = "https://files.pythonhosted.org/packages/00/71/3a69e86f3eafe8c7a59d008d245888051005bd657760e96d5fbfb0b740c2/tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15", size = 247973, upload-time = "2026-03-25T20:21:46.937Z" }, - { url = "https://files.pythonhosted.org/packages/67/50/361e986652847fec4bd5e4a0208752fbe64689c603c7ae5ea7cb16b1c0ca/tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba", size = 256223, upload-time = "2026-03-25T20:21:48.467Z" }, - { url = "https://files.pythonhosted.org/packages/8c/9a/b4173689a9203472e5467217e0154b00e260621caa227b6fa01feab16998/tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6", size = 98973, upload-time = "2026-03-25T20:21:49.526Z" }, - { url = "https://files.pythonhosted.org/packages/14/58/640ac93bf230cd27d002462c9af0d837779f8773bc03dee06b5835208214/tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7", size = 109082, upload-time = "2026-03-25T20:21:50.506Z" }, - { url = "https://files.pythonhosted.org/packages/d5/2f/702d5e05b227401c1068f0d386d79a589bb12bf64c3d2c72ce0631e3bc49/tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232", size = 96490, upload-time = "2026-03-25T20:21:51.474Z" }, - { url = "https://files.pythonhosted.org/packages/45/4b/b877b05c8ba62927d9865dd980e34a755de541eb65fffba52b4cc495d4d2/tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4", size = 164263, upload-time = "2026-03-25T20:21:52.543Z" }, - { url = "https://files.pythonhosted.org/packages/24/79/6ab420d37a270b89f7195dec5448f79400d9e9c1826df982f3f8e97b24fd/tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c", size = 160736, upload-time = "2026-03-25T20:21:53.674Z" }, - { url = "https://files.pythonhosted.org/packages/02/e0/3630057d8eb170310785723ed5adcdfb7d50cb7e6455f85ba8a3deed642b/tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d", size = 270717, upload-time = "2026-03-25T20:21:55.129Z" }, - { url = "https://files.pythonhosted.org/packages/7a/b4/1613716072e544d1a7891f548d8f9ec6ce2faf42ca65acae01d76ea06bb0/tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41", size = 278461, upload-time = "2026-03-25T20:21:56.228Z" }, - { url = "https://files.pythonhosted.org/packages/05/38/30f541baf6a3f6df77b3df16b01ba319221389e2da59427e221ef417ac0c/tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c", size = 274855, upload-time = "2026-03-25T20:21:57.653Z" }, - { url = "https://files.pythonhosted.org/packages/77/a3/ec9dd4fd2c38e98de34223b995a3b34813e6bdadf86c75314c928350ed14/tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f", size = 283144, upload-time = "2026-03-25T20:21:59.089Z" }, - { url = "https://files.pythonhosted.org/packages/ef/be/605a6261cac79fba2ec0c9827e986e00323a1945700969b8ee0b30d85453/tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8", size = 108683, upload-time = "2026-03-25T20:22:00.214Z" }, - { url = "https://files.pythonhosted.org/packages/12/64/da524626d3b9cc40c168a13da8335fe1c51be12c0a63685cc6db7308daae/tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26", size = 121196, upload-time = "2026-03-25T20:22:01.169Z" }, - { url = "https://files.pythonhosted.org/packages/5a/cd/e80b62269fc78fc36c9af5a6b89c835baa8af28ff5ad28c7028d60860320/tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396", size = 100393, upload-time = "2026-03-25T20:22:02.137Z" }, - { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, -] - -[[package]] -name = "typing-extensions" -version = "4.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, -] - -[[package]] -name = "wcmatch" -version = "11.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "bracex" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/57/43/30e407989e313677dbb9d5f045f966549a7254834571e342eaa4b55cc67b/wcmatch-11.0.1.tar.gz", hash = "sha256:1ea2b4fa678b8ca268253798d5963935df39132d47c3e241c0a0732224005e7d", size = 144662, upload-time = "2026-08-14T15:20:40.477Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/77/7a02b0f05b3ffcdbef9719ce3ee0b508d6a29b58e95299f1580055671db3/wcmatch-11.0.1-py3-none-any.whl", hash = "sha256:fd149ecddb9f0a88ea780017d6dde17c994e494e7f7303d4e3c9d6251f978f4b", size = 43449, upload-time = "2026-08-14T15:20:39.379Z" }, -]